<commit_before>use socket::Socket;

pub enum Unit {
    RAW,
    VOLTS,
}

impl ::std::fmt::Display for Unit {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Unit::RAW => "RAW",
            &Unit::VOLTS => "VOLTS",
        };

        write!(f, "{}", display)
    }
}

pub struct Data {
    socket: Socket,
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: socket,
        }
    }

    pub fn get_write_pointer(&mut self) -> u32 {
        self.socket.send("ACQ:WPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn get_trigger_position(&mut self) -> u32 {
        self.socket.send("ACQ:TPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn set_units(&mut self, unit: Unit) {
        self.socket.send(format!("ACQ:DATA:UNITS {}", unit));
    }

    pub fn set_format(&mut self, format: &str) {
        self.socket.send(format!("ACQ:DATA:FORMAT {}", format));
    }

    pub fn read_slice(&mut self, source: u8, start: u32, end: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:END? {},{}", source, start, end));

        self.socket.receive()
    }

    pub fn read(&mut self, source: u8, start: u32, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:N? {},{}", source, start, len));

        self.socket.receive()
    }

    pub fn read_all(&mut self, source: u8) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA?", source));

        self.socket.receive()
    }

    pub fn read_oldest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:OLD:N? {}", source, len));

        self.socket.receive()
    }

    pub fn read_latest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:LAT:N? {}", source, len));

        self.socket.receive()
    }

    pub fn buffer_size(&mut self) -> u32 {
        self.socket.send("ACQ:BUF:SIZE?");

        self.socket.receive()
            .parse()
            .unwrap()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_write_pointer(), 1024);
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_trigger_position(), 512);
    }

    #[test]
    fn test_set_units() {
        let (rx, mut data) = create_data();

        data.set_units(::data::Unit::VOLTS);
        assert_eq!("ACQ:DATA:UNITS VOLTS\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_format() {
        let (rx, mut data) = create_data();

        data.set_format("FLOAT");
        assert_eq!("ACQ:DATA:FORMAT FLOAT\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_read_slice() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_slice(1, 10, 13), "{123,231,-231}");
    }

    #[test]
    fn test_read() {
        let (_, mut data) = create_data();

        assert_eq!(data.read(1, 10, 3), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_all() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_all(1), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_oldest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_oldest(1, 2), "{3.2,-1.2}");
    }

    #[test]
    fn test_read_latest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_latest(1, 2), "{1.2,3.2}");
    }

    #[test]
    fn test_buffer_size() {
        let (_, mut data) = create_data();

        assert_eq!(data.buffer_size(), 16384);
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::data::Data::new(socket))
    }
}
<commit_msg>[data] Add data::Format enum<commit_after>use socket::Socket;

pub enum Unit {
    RAW,
    VOLTS,
}

impl ::std::fmt::Display for Unit {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Unit::RAW => "RAW",
            &Unit::VOLTS => "VOLTS",
        };

        write!(f, "{}", display)
    }
}

pub enum Format {
    FLOAT,
    ASCII,
}

impl ::std::fmt::Display for Format {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Format::FLOAT => "FLOAT",
            &Format::ASCII => "ASCII",
        };

        write!(f, "{}", display)
    }
}

pub struct Data {
    socket: Socket,
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: socket,
        }
    }

    pub fn get_write_pointer(&mut self) -> u32 {
        self.socket.send("ACQ:WPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn get_trigger_position(&mut self) -> u32 {
        self.socket.send("ACQ:TPOS?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn set_units(&mut self, unit: Unit) {
        self.socket.send(format!("ACQ:DATA:UNITS {}", unit));
    }

    pub fn set_format(&mut self, format: Format) {
        self.socket.send(format!("ACQ:DATA:FORMAT {}", format));
    }

    pub fn read_slice(&mut self, source: u8, start: u32, end: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:END? {},{}", source, start, end));

        self.socket.receive()
    }

    pub fn read(&mut self, source: u8, start: u32, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:STA:N? {},{}", source, start, len));

        self.socket.receive()
    }

    pub fn read_all(&mut self, source: u8) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA?", source));

        self.socket.receive()
    }

    pub fn read_oldest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:OLD:N? {}", source, len));

        self.socket.receive()
    }

    pub fn read_latest(&mut self, source: u8, len: u32) -> String {
        self.socket.send(format!("ACQ:SOUR{}:DATA:LAT:N? {}", source, len));

        self.socket.receive()
    }

    pub fn buffer_size(&mut self) -> u32 {
        self.socket.send("ACQ:BUF:SIZE?");

        self.socket.receive()
            .parse()
            .unwrap()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_write_pointer(), 1024);
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, mut data) = create_data();

        assert_eq!(data.get_trigger_position(), 512);
    }

    #[test]
    fn test_set_units() {
        let (rx, mut data) = create_data();

        data.set_units(::data::Unit::VOLTS);
        assert_eq!("ACQ:DATA:UNITS VOLTS\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_format() {
        let (rx, mut data) = create_data();

        data.set_format(::data::Format::FLOAT);
        assert_eq!("ACQ:DATA:FORMAT FLOAT\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_read_slice() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_slice(1, 10, 13), "{123,231,-231}");
    }

    #[test]
    fn test_read() {
        let (_, mut data) = create_data();

        assert_eq!(data.read(1, 10, 3), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_all() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_all(1), "{1.2,3.2,-1.2}");
    }

    #[test]
    fn test_read_oldest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_oldest(1, 2), "{3.2,-1.2}");
    }

    #[test]
    fn test_read_latest() {
        let (_, mut data) = create_data();

        assert_eq!(data.read_latest(1, 2), "{1.2,3.2}");
    }

    #[test]
    fn test_buffer_size() {
        let (_, mut data) = create_data();

        assert_eq!(data.buffer_size(), 16384);
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::data::Data::new(socket))
    }
}
<|endoftext|>


<commit_before>use crate::ops::Try;
use crate::usize;

use super::super::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};

/// An iterator that links two iterators together, in a chain.
///
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`chain`]: trait.Iterator.html#method.chain
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<A, B> {
    a: A,
    b: B,
    state: ChainState,
}
impl<A, B> Chain<A, B> {
    pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
        Chain { a, b, state: ChainState::Both }
    }
}

// The iterator protocol specifies that iteration ends with the return value
// `None` from `.next()` (or `.next_back()`) and it is unspecified what
// further calls return. The chain adaptor must account for this since it uses
// two subiterators.
//
//  It uses three states:
//
//  - Both: `a` and `b` are remaining
//  - Front: `a` remaining
//  - Back: `b` remaining
//
//  The fourth state (neither iterator is remaining) only occurs after Chain has
//  returned None once, so we don't need to store this state.
#[derive(Clone, Debug)]
enum ChainState {
    // both front and back iterator are remaining
    Both,
    // only front is remaining
    Front,
    // only back is remaining
    Back,
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> Iterator for Chain<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
{
    type Item = A::Item;

    #[inline]
    fn next(&mut self) -> Option<A::Item> {
        match self.state {
            ChainState::Both => match self.a.next() {
                elt @ Some(..) => elt,
                None => {
                    self.state = ChainState::Back;
                    self.b.next()
                }
            },
            ChainState::Front => self.a.next(),
            ChainState::Back => self.b.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(self) -> usize {
        match self.state {
            ChainState::Both => self.a.count() + self.b.count(),
            ChainState::Front => self.a.count(),
            ChainState::Back => self.b.count(),
        }
    }

    fn try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        let mut accum = init;
        match self.state {
            ChainState::Both | ChainState::Front => {
                accum = self.a.try_fold(accum, &mut f)?;
                if let ChainState::Both = self.state {
                    self.state = ChainState::Back;
                }
            }
            _ => {}
        }
        if let ChainState::Back = self.state {
            accum = self.b.try_fold(accum, &mut f)?;
        }
        Try::from_ok(accum)
    }

    fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        let mut accum = init;
        match self.state {
            ChainState::Both | ChainState::Front => {
                accum = self.a.fold(accum, &mut f);
            }
            _ => {}
        }
        match self.state {
            ChainState::Both | ChainState::Back => {
                accum = self.b.fold(accum, &mut f);
            }
            _ => {}
        }
        accum
    }

    #[inline]
    fn nth(&mut self, mut n: usize) -> Option<A::Item> {
        match self.state {
            ChainState::Both | ChainState::Front => {
                for x in self.a.by_ref() {
                    if n == 0 {
                        return Some(x);
                    }
                    n -= 1;
                }
                if let ChainState::Both = self.state {
                    self.state = ChainState::Back;
                }
            }
            ChainState::Back => {}
        }
        if let ChainState::Back = self.state { self.b.nth(n) } else { None }
    }

    #[inline]
    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match self.state {
            ChainState::Both => match self.a.find(&mut predicate) {
                None => {
                    self.state = ChainState::Back;
                    self.b.find(predicate)
                }
                v => v,
            },
            ChainState::Front => self.a.find(predicate),
            ChainState::Back => self.b.find(predicate),
        }
    }

    #[inline]
    fn last(self) -> Option<A::Item> {
        match self.state {
            ChainState::Both => {
                // Must exhaust a before b.
                let a_last = self.a.last();
                let b_last = self.b.last();
                b_last.or(a_last)
            }
            ChainState::Front => self.a.last(),
            ChainState::Back => self.b.last(),
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.state {
            ChainState::Both => {
                let (a_lower, a_upper) = self.a.size_hint();
                let (b_lower, b_upper) = self.b.size_hint();

                let lower = a_lower.saturating_add(b_lower);

                let upper = match (a_upper, b_upper) {
                    (Some(x), Some(y)) => x.checked_add(y),
                    _ => None,
                };

                (lower, upper)
            }
            ChainState::Front => self.a.size_hint(),
            ChainState::Back => self.b.size_hint(),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> DoubleEndedIterator for Chain<A, B>
where
    A: DoubleEndedIterator,
    B: DoubleEndedIterator<Item = A::Item>,
{
    #[inline]
    fn next_back(&mut self) -> Option<A::Item> {
        match self.state {
            ChainState::Both => match self.b.next_back() {
                elt @ Some(..) => elt,
                None => {
                    self.state = ChainState::Front;
                    self.a.next_back()
                }
            },
            ChainState::Front => self.a.next_back(),
            ChainState::Back => self.b.next_back(),
        }
    }

    #[inline]
    fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
        match self.state {
            ChainState::Both | ChainState::Back => {
                for x in self.b.by_ref().rev() {
                    if n == 0 {
                        return Some(x);
                    }
                    n -= 1;
                }
                if let ChainState::Both = self.state {
                    self.state = ChainState::Front;
                }
            }
            ChainState::Front => {}
        }
        if let ChainState::Front = self.state { self.a.nth_back(n) } else { None }
    }

    fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        let mut accum = init;
        match self.state {
            ChainState::Both | ChainState::Back => {
                accum = self.b.try_rfold(accum, &mut f)?;
                if let ChainState::Both = self.state {
                    self.state = ChainState::Front;
                }
            }
            _ => {}
        }
        if let ChainState::Front = self.state {
            accum = self.a.try_rfold(accum, &mut f)?;
        }
        Try::from_ok(accum)
    }

    fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        let mut accum = init;
        match self.state {
            ChainState::Both | ChainState::Back => {
                accum = self.b.rfold(accum, &mut f);
            }
            _ => {}
        }
        match self.state {
            ChainState::Both | ChainState::Front => {
                accum = self.a.rfold(accum, &mut f);
            }
            _ => {}
        }
        accum
    }
}

// Note: *both* must be fused to handle double-ended iterators.
#[stable(feature = "fused", since = "1.26.0")]
impl<A, B> FusedIterator for Chain<A, B>
where
    A: FusedIterator,
    B: FusedIterator<Item = A::Item>,
{
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, B> TrustedLen for Chain<A, B>
where
    A: TrustedLen,
    B: TrustedLen<Item = A::Item>,
{
}
<commit_msg>Rollup merge of #70896 - cuviper:optional-chain, r=scottmcm<commit_after>use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
use crate::ops::Try;
use crate::usize;

/// An iterator that links two iterators together, in a chain.
///
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`chain`]: trait.Iterator.html#method.chain
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<A, B> {
    // These are "fused" with `Option` so we don't need separate state to track which part is
    // already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse`
    // adapter because its specialization for `FusedIterator` unconditionally descends into the
    // iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
    // hurts compiler performance to add more iterator layers to `Chain`.
    a: Option<A>,
    b: Option<B>,
}
impl<A, B> Chain<A, B> {
    pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
        Chain { a: Some(a), b: Some(b) }
    }
}

/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
    ($self:ident . $iter:ident . $($call:tt)+) => {
        match $self.$iter {
            Some(ref mut iter) => match iter.$($call)+ {
                None => {
                    $self.$iter = None;
                    None
                }
                item => item,
            },
            None => None,
        }
    };
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> Iterator for Chain<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
{
    type Item = A::Item;

    #[inline]
    fn next(&mut self) -> Option<A::Item> {
        match fuse!(self.a.next()) {
            None => fuse!(self.b.next()),
            item => item,
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(self) -> usize {
        let a_count = match self.a {
            Some(a) => a.count(),
            None => 0,
        };
        let b_count = match self.b {
            Some(b) => b.count(),
            None => 0,
        };
        a_count + b_count
    }

    fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut a) = self.a {
            acc = a.try_fold(acc, &mut f)?;
            self.a = None;
        }
        if let Some(ref mut b) = self.b {
            acc = b.try_fold(acc, f)?;
            self.b = None;
        }
        Try::from_ok(acc)
    }

    fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(a) = self.a {
            acc = a.fold(acc, &mut f);
        }
        if let Some(b) = self.b {
            acc = b.fold(acc, f);
        }
        acc
    }

    #[inline]
    fn nth(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut a) = self.a {
            while let Some(x) = a.next() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.a = None;
        }
        fuse!(self.b.nth(n))
    }

    #[inline]
    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.a.find(&mut predicate)) {
            None => fuse!(self.b.find(predicate)),
            item => item,
        }
    }

    #[inline]
    fn last(self) -> Option<A::Item> {
        // Must exhaust a before b.
        let a_last = match self.a {
            Some(a) => a.last(),
            None => None,
        };
        let b_last = match self.b {
            Some(b) => b.last(),
            None => None,
        };
        b_last.or(a_last)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            Chain { a: Some(a), b: Some(b) } => {
                let (a_lower, a_upper) = a.size_hint();
                let (b_lower, b_upper) = b.size_hint();

                let lower = a_lower.saturating_add(b_lower);

                let upper = match (a_upper, b_upper) {
                    (Some(x), Some(y)) => x.checked_add(y),
                    _ => None,
                };

                (lower, upper)
            }
            Chain { a: Some(a), b: None } => a.size_hint(),
            Chain { a: None, b: Some(b) } => b.size_hint(),
            Chain { a: None, b: None } => (0, Some(0)),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> DoubleEndedIterator for Chain<A, B>
where
    A: DoubleEndedIterator,
    B: DoubleEndedIterator<Item = A::Item>,
{
    #[inline]
    fn next_back(&mut self) -> Option<A::Item> {
        match fuse!(self.b.next_back()) {
            None => fuse!(self.a.next_back()),
            item => item,
        }
    }

    #[inline]
    fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut b) = self.b {
            while let Some(x) = b.next_back() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.b = None;
        }
        fuse!(self.a.nth_back(n))
    }

    #[inline]
    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.b.rfind(&mut predicate)) {
            None => fuse!(self.a.rfind(predicate)),
            item => item,
        }
    }

    fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut b) = self.b {
            acc = b.try_rfold(acc, &mut f)?;
            self.b = None;
        }
        if let Some(ref mut a) = self.a {
            acc = a.try_rfold(acc, f)?;
            self.a = None;
        }
        Try::from_ok(acc)
    }

    fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(b) = self.b {
            acc = b.rfold(acc, &mut f);
        }
        if let Some(a) = self.a {
            acc = a.rfold(acc, f);
        }
        acc
    }
}

// Note: *both* must be fused to handle double-ended iterators.
// Now that we "fuse" both sides, we *could* implement this unconditionally,
// but we should be cautious about committing to that in the public API.
#[stable(feature = "fused", since = "1.26.0")]
impl<A, B> FusedIterator for Chain<A, B>
where
    A: FusedIterator,
    B: FusedIterator<Item = A::Item>,
{
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, B> TrustedLen for Chain<A, B>
where
    A: TrustedLen,
    B: TrustedLen<Item = A::Item>,
{
}
<|endoftext|>


<commit_before>// Copyright 2014 Rich Lane.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern mod extra;
extern mod cgmath;
extern mod noise;

use std;
use std::num::clamp;

use extra::time::precise_time_ns;

use cgmath::vector::Vec3;

use noise::Perlin;

use CHUNK_SIZE;

#[repr(u8)]
#[deriving(Eq)]
pub enum BlockType {
    BlockAir = 0,
    BlockGrass = 1,
    BlockStone = 2,
    BlockDirt = 3,
    BlockWater = 4,
}

pub struct Block {
    blocktype: BlockType,
}

impl Block {
    pub fn is_opaque(&self) -> bool {
        self.blocktype != BlockAir
    }
}

pub struct Terrain {
    priv blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

impl Terrain {
    pub fn gen(seed: u32, p: Vec3<f64>) -> ~Terrain {
        let def_block = Block { blocktype: BlockAir };
        let mut t = ~Terrain {
            blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
        };

        let start_time = precise_time_ns();

        let perlin1 = Perlin::from_seed([seed as uint]);
        let perlin2 = Perlin::from_seed([seed as uint * 7]);
        let perlin3 = Perlin::from_seed([seed as uint * 13]);
        let perlin4 = Perlin::from_seed([seed as uint * 17]);

        for block_x in std::iter::range(0, CHUNK_SIZE) {
            for block_z in std::iter::range(0, CHUNK_SIZE) {
                let noise1 = perlin1.gen([
                    (p.x + block_x as f64) * 0.07,
                    (p.z + block_z as f64) * 0.04
                ]);
                let noise2 = perlin2.gen([
                    (p.x + block_x as f64) * 0.05,
                    (p.z + block_z as f64) * 0.05
                ]);
                let noise3 = perlin3.gen([
                    (p.x + block_x as f64) * 0.005,
                    (p.z + block_z as f64) * 0.005
                ]);
                let noise4 = perlin4.gen([
                    (p.x + block_x as f64) * 0.001,
                    (p.z + block_z as f64) * 0.001
                ]);

                let base_height = 15.0;
                let base_variance = 10.0;
                let height = clamp(
                    (
                        base_height +
                        noise4 * 10.0 +
                        base_variance *
                            std::num::pow(noise3 + 1.0, 2.5) *
                            noise1
                    ) as int,
                    1, CHUNK_SIZE - 1);

                for y in range(0, height) {
                    let block = t.get_mut(block_x, y, block_z);

                    let dirt_height = (4.0 + noise2 * 8.0) as int;
                    if (height <= 20) && (y + dirt_height >= height) {
                        if y < height - 2 {
                            block.blocktype = BlockDirt;
                        } else {
                            block.blocktype = BlockGrass;
                        }
                    } else {
                        block.blocktype = BlockStone;
                    }
                }

                let water_height = 10;
                for y in range(height, water_height) {
                    let block = t.get_mut(block_x, y, block_z);
                    block.blocktype = BlockWater;
                }

                for block_y in std::iter::range(0, CHUNK_SIZE) {
                    let block = t.get_mut(block_x, block_y, block_z);

                    if (p.y + block_y as f64) <= 1.0 ||
                       block.blocktype == BlockAir {
                        continue;
                    }

                    let cave = perlin1.gen([
                        (p.x + block_x as f64) * 0.05,
                        (p.y + block_y as f64) * 0.1,
                        (p.z + block_z as f64) * 0.05]);

                    if cave > 0.5 {
                        block.blocktype = BlockAir;
                    }
                }

            }
        }

        let end_time = precise_time_ns();

        println!("terrain gen : {}us",
                (end_time - start_time)/1000);

        return t;
    }

    pub fn get<'a>(&'a self, x: int, y: int, z: int) -> Option<&'a Block> {
        if x < 0 || x >= CHUNK_SIZE || y < 0 || y >= CHUNK_SIZE || z < 0 || z >= CHUNK_SIZE {
            None
        } else {
            Some(&self.blocks[x][y][z])
        }
    }

    pub fn get_mut<'a>(&'a mut self, x: int, y: int, z: int) -> &'a mut Block {
        &mut self.blocks[x][y][z]
    }

}
<commit_msg>terrain: store neighboring blocks<commit_after>// Copyright 2014 Rich Lane.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern mod extra;
extern mod cgmath;
extern mod noise;

use std;
use std::num::clamp;

use extra::time::precise_time_ns;

use cgmath::vector::Vec3;

use noise::Perlin;

use CHUNK_SIZE;

#[repr(u8)]
#[deriving(Eq)]
pub enum BlockType {
    BlockAir = 0,
    BlockGrass = 1,
    BlockStone = 2,
    BlockDirt = 3,
    BlockWater = 4,
}

pub struct Block {
    blocktype: BlockType,
}

impl Block {
    pub fn is_opaque(&self) -> bool {
        self.blocktype != BlockAir
    }
}

pub struct Terrain {
    priv blocks: [[[Block, ..CHUNK_SIZE+2], ..CHUNK_SIZE+2], ..CHUNK_SIZE+2],
}

impl Terrain {
    pub fn gen(seed: u32, p: Vec3<f64>) -> ~Terrain {
        let def_block = Block { blocktype: BlockAir };
        let mut t = ~Terrain {
            blocks: [[[def_block, ..CHUNK_SIZE+2], ..CHUNK_SIZE+2], ..CHUNK_SIZE+2],
        };

        let start_time = precise_time_ns();

        let perlin1 = Perlin::from_seed([seed as uint]);
        let perlin2 = Perlin::from_seed([seed as uint * 7]);
        let perlin3 = Perlin::from_seed([seed as uint * 13]);
        let perlin4 = Perlin::from_seed([seed as uint * 17]);

        for block_x in std::iter::range(-1, CHUNK_SIZE+1) {
            for block_z in std::iter::range(-1, CHUNK_SIZE+1) {
                let noise1 = perlin1.gen([
                    (p.x + block_x as f64) * 0.07,
                    (p.z + block_z as f64) * 0.04
                ]);
                let noise2 = perlin2.gen([
                    (p.x + block_x as f64) * 0.05,
                    (p.z + block_z as f64) * 0.05
                ]);
                let noise3 = perlin3.gen([
                    (p.x + block_x as f64) * 0.005,
                    (p.z + block_z as f64) * 0.005
                ]);
                let noise4 = perlin4.gen([
                    (p.x + block_x as f64) * 0.001,
                    (p.z + block_z as f64) * 0.001
                ]);

                let base_height = 15.0;
                let base_variance = 10.0;
                let height = clamp(
                    (
                        base_height +
                        noise4 * 10.0 +
                        base_variance *
                            std::num::pow(noise3 + 1.0, 2.5) *
                            noise1
                    ) as int,
                    1, CHUNK_SIZE - 1);

                for y in range(0, height) {
                    let block = t.get_mut(block_x, y, block_z);

                    let dirt_height = (4.0 + noise2 * 8.0) as int;
                    if (height <= 20) && (y + dirt_height >= height) {
                        if y < height - 2 {
                            block.blocktype = BlockDirt;
                        } else {
                            block.blocktype = BlockGrass;
                        }
                    } else {
                        block.blocktype = BlockStone;
                    }
                }

                let water_height = 10;
                for y in range(height, water_height) {
                    let block = t.get_mut(block_x, y, block_z);
                    block.blocktype = BlockWater;
                }

                for block_y in std::iter::range(0, CHUNK_SIZE) {
                    let block = t.get_mut(block_x, block_y, block_z);

                    if (p.y + block_y as f64) <= 1.0 ||
                       block.blocktype == BlockAir {
                        continue;
                    }

                    let cave = perlin1.gen([
                        (p.x + block_x as f64) * 0.05,
                        (p.y + block_y as f64) * 0.1,
                        (p.z + block_z as f64) * 0.05]);

                    if cave > 0.5 {
                        block.blocktype = BlockAir;
                    }
                }

            }
        }

        let end_time = precise_time_ns();

        println!("terrain gen : {}us",
                (end_time - start_time)/1000);

        return t;
    }

    pub fn get<'a>(&'a self, x: int, y: int, z: int) -> Option<&'a Block> {
        if x < -1 || x >= CHUNK_SIZE+1 || y < -1 || y >= CHUNK_SIZE+1 || z < -1 || z >= CHUNK_SIZE+1 {
            None
        } else {
            Some(&self.blocks[x+1][y+1][z+1])
        }
    }

    pub fn get_mut<'a>(&'a mut self, x: int, y: int, z: int) -> &'a mut Block {
        &mut self.blocks[x+1][y+1][z+1]
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Generating numbers between two others.

// this is surprisingly complicated to be both generic & correct

use core::prelude::*;
use core::num::Bounded;

use Rng;
use distributions::{Sample, IndependentSample};

/// Sample values uniformly between two bounds.
///
/// This gives a uniform distribution (assuming the RNG used to sample
/// it is itself uniform & the `SampleRange` implementation for the
/// given type is correct), even for edge cases like `low = 0u8`,
/// `high = 170u8`, for which a naive modulo operation would return
/// numbers less than 85 with double the probability to those greater
/// than 85.
///
/// Types should attempt to sample in `[low, high)`, i.e., not
/// including `high`, but this may be very difficult. All the
/// primitive integer types satisfy this property, and the float types
/// normally satisfy it, but rounding may mean `high` can occur.
///
/// # Example
///
/// ```rust
/// use std::rand::distributions::{IndependentSample, Range};
///
/// fn main() {
///     let between = Range::new(10u, 10000u);
///     let mut rng = std::rand::task_rng();
///     let mut sum = 0;
///     for _ in range(0u, 1000) {
///         sum += between.ind_sample(&mut rng);
///     }
///     println!("{}", sum);
/// }
/// ```
pub struct Range<X> {
    low: X,
    range: X,
    accept_zone: X
}

impl<X: SampleRange + PartialOrd> Range<X> {
    /// Create a new `Range` instance that samples uniformly from
    /// `[low, high)`. Fails if `low >= high`.
    pub fn new(low: X, high: X) -> Range<X> {
        assert!(low < high, "Range::new called with `low >= high`");
        SampleRange::construct_range(low, high)
    }
}

impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
    #[inline]
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        SampleRange::sample_range(self, rng)
    }
}

/// The helper trait for types that have a sensible way to sample
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
pub trait SampleRange {
    /// Construct the `Range` object that `sample_range`
    /// requires. This should not ever be called directly, only via
    /// `Range::new`, which will check that `low < high`, so this
    /// function doesn't have to repeat the check.
    fn construct_range(low: Self, high: Self) -> Range<Self>;

    /// Sample a value from the given `Range` with the given `Rng` as
    /// a source of randomness.
    fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}

macro_rules! integer_impl {
    ($ty:ty, $unsigned:ty) => {
        impl SampleRange for $ty {
            // we play free and fast with unsigned vs signed here
            // (when $ty is signed), but that's fine, since the
            // contract of this macro is for $ty and $unsigned to be
            // "bit-equal", so casting between them is a no-op & a
            // bijection.

            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                let range = high as $unsigned - low as $unsigned;
                let unsigned_max: $unsigned = Bounded::max_value();

                // this is the largest number that fits into $unsigned
                // that `range` divides evenly, so, if we've sampled
                // `n` uniformly from this region, then `n % range` is
                // uniform in [0, range)
                let zone = unsigned_max - unsigned_max % range;

                Range {
                    low: low,
                    range: range as $ty,
                    accept_zone: zone as $ty
                }
            }
            #[inline]
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                loop {
                    // rejection sample
                    let v = rng.gen::<$unsigned>();
                    // until we find something that fits into the
                    // region which r.range evenly divides (this will
                    // be uniformly distributed)
                    if v < r.accept_zone as $unsigned {
                        // and return it, with some adjustments
                        return r.low + (v % r.range as $unsigned) as $ty;
                    }
                }
            }
        }
    }
}

integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { int, uint }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { uint, uint }

macro_rules! float_impl {
    ($ty:ty) => {
        impl SampleRange for $ty {
            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                Range {
                    low: low,
                    range: high - low,
                    accept_zone: 0.0 // unused
                }
            }
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                r.low + r.range * rng.gen()
            }
        }
    }
}

float_impl! { f32 }
float_impl! { f64 }

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use distributions::{Sample, IndependentSample};
    use super::Range;
    use std::num::Bounded;

    #[should_fail]
    #[test]
    fn test_range_bad_limits_equal() {
        Range::new(10i, 10i);
    }
    #[should_fail]
    #[test]
    fn test_range_bad_limits_flipped() {
        Range::new(10i, 5i);
    }

    #[test]
    fn test_integers() {
        let mut rng = ::test::rng();
        macro_rules! t (
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = [(0, 10),
                                           (10, 127),
                                           (Bounded::min_value(), Bounded::max_value())];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in range(0u, 1000) {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        );
        t!(i8, i16, i32, i64, int,
           u8, u16, u32, u64, uint)
    }

    #[test]
    fn test_floats() {
        let mut rng = ::test::rng();
        macro_rules! t (
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = [(0.0, 100.0),
                                           (-1e35, -1e25),
                                           (1e-35, 1e-25),
                                           (-1e35, 1e35)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in range(0u, 1000) {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        );

        t!(f32, f64)
    }

}
<commit_msg>Deprecate Bounded trait<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Generating numbers between two others.

// this is surprisingly complicated to be both generic & correct

use core::prelude::*;

use Rng;
use distributions::{Sample, IndependentSample};

/// Sample values uniformly between two bounds.
///
/// This gives a uniform distribution (assuming the RNG used to sample
/// it is itself uniform & the `SampleRange` implementation for the
/// given type is correct), even for edge cases like `low = 0u8`,
/// `high = 170u8`, for which a naive modulo operation would return
/// numbers less than 85 with double the probability to those greater
/// than 85.
///
/// Types should attempt to sample in `[low, high)`, i.e., not
/// including `high`, but this may be very difficult. All the
/// primitive integer types satisfy this property, and the float types
/// normally satisfy it, but rounding may mean `high` can occur.
///
/// # Example
///
/// ```rust
/// use std::rand::distributions::{IndependentSample, Range};
///
/// fn main() {
///     let between = Range::new(10u, 10000u);
///     let mut rng = std::rand::task_rng();
///     let mut sum = 0;
///     for _ in range(0u, 1000) {
///         sum += between.ind_sample(&mut rng);
///     }
///     println!("{}", sum);
/// }
/// ```
pub struct Range<X> {
    low: X,
    range: X,
    accept_zone: X
}

impl<X: SampleRange + PartialOrd> Range<X> {
    /// Create a new `Range` instance that samples uniformly from
    /// `[low, high)`. Fails if `low >= high`.
    pub fn new(low: X, high: X) -> Range<X> {
        assert!(low < high, "Range::new called with `low >= high`");
        SampleRange::construct_range(low, high)
    }
}

impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
    #[inline]
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        SampleRange::sample_range(self, rng)
    }
}

/// The helper trait for types that have a sensible way to sample
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
pub trait SampleRange {
    /// Construct the `Range` object that `sample_range`
    /// requires. This should not ever be called directly, only via
    /// `Range::new`, which will check that `low < high`, so this
    /// function doesn't have to repeat the check.
    fn construct_range(low: Self, high: Self) -> Range<Self>;

    /// Sample a value from the given `Range` with the given `Rng` as
    /// a source of randomness.
    fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}

macro_rules! integer_impl {
    ($ty:ty, $unsigned:ty) => {
        impl SampleRange for $ty {
            // we play free and fast with unsigned vs signed here
            // (when $ty is signed), but that's fine, since the
            // contract of this macro is for $ty and $unsigned to be
            // "bit-equal", so casting between them is a no-op & a
            // bijection.

            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                let range = high as $unsigned - low as $unsigned;
                let unsigned_max: $unsigned = Int::max_value();

                // this is the largest number that fits into $unsigned
                // that `range` divides evenly, so, if we've sampled
                // `n` uniformly from this region, then `n % range` is
                // uniform in [0, range)
                let zone = unsigned_max - unsigned_max % range;

                Range {
                    low: low,
                    range: range as $ty,
                    accept_zone: zone as $ty
                }
            }
            #[inline]
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                loop {
                    // rejection sample
                    let v = rng.gen::<$unsigned>();
                    // until we find something that fits into the
                    // region which r.range evenly divides (this will
                    // be uniformly distributed)
                    if v < r.accept_zone as $unsigned {
                        // and return it, with some adjustments
                        return r.low + (v % r.range as $unsigned) as $ty;
                    }
                }
            }
        }
    }
}

integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { int, uint }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { uint, uint }

macro_rules! float_impl {
    ($ty:ty) => {
        impl SampleRange for $ty {
            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                Range {
                    low: low,
                    range: high - low,
                    accept_zone: 0.0 // unused
                }
            }
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                r.low + r.range * rng.gen()
            }
        }
    }
}

float_impl! { f32 }
float_impl! { f64 }

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use distributions::{Sample, IndependentSample};
    use super::Range;

    #[should_fail]
    #[test]
    fn test_range_bad_limits_equal() {
        Range::new(10i, 10i);
    }
    #[should_fail]
    #[test]
    fn test_range_bad_limits_flipped() {
        Range::new(10i, 5i);
    }

    #[test]
    fn test_integers() {
        let mut rng = ::test::rng();
        macro_rules! t (
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = [(0, 10),
                                           (10, 127),
                                           (Int::min_value(), Int::max_value())];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in range(0u, 1000) {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        );
        t!(i8, i16, i32, i64, int,
           u8, u16, u32, u64, uint)
    }

    #[test]
    fn test_floats() {
        let mut rng = ::test::rng();
        macro_rules! t (
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = [(0.0, 100.0),
                                           (-1e35, -1e25),
                                           (1e-35, 1e-25),
                                           (-1e35, 1e35)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in range(0u, 1000) {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        );

        t!(f32, f64)
    }

}
<|endoftext|>


<commit_before>//! This pass checks HIR bodies that may be evaluated at compile-time (e.g., `const`, `static`,
//! `const fn`) for structured control flow (e.g. `if`, `while`), which is forbidden in a const
//! context.
//!
//! By the time the MIR const-checker runs, these high-level constructs have been lowered to
//! control-flow primitives (e.g., `Goto`, `SwitchInt`), making it tough to properly attribute
//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
//! through, but errors for structured control flow in a `const` should be emitted here.

use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};

/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
    Loop(hir::LoopSource),
    Match(hir::MatchSource),
    OrPattern,
}

impl NonConstExpr {
    fn name(self) -> String {
        match self {
            Self::Loop(src) => format!("`{}`", src.name()),
            Self::Match(src) => format!("`{}`", src.name()),
            Self::OrPattern => "or-pattern".to_string(),
        }
    }

    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
        use hir::LoopSource::*;
        use hir::MatchSource::*;

        let gates: &[_] = match self {
            Self::Match(Normal)
            | Self::Match(IfDesugar { .. })
            | Self::Match(IfLetDesugar { .. })
            | Self::OrPattern => &[sym::const_if_match],

            Self::Loop(Loop) => &[sym::const_loop],

            Self::Loop(While)
            | Self::Loop(WhileLet)
            | Self::Match(WhileDesugar | WhileLetDesugar) => {
                &[sym::const_loop, sym::const_if_match]
            }

            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
            // so they are not yet allowed with `#![feature(const_loop)]`.
            _ => return None,
        };

        Some(gates)
    }
}

fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    let mut vis = CheckConstVisitor::new(tcx);
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
}

pub(crate) fn provide(providers: &mut Providers<'_>) {
    *providers = Providers { check_mod_const_bodies, ..*providers };
}

#[derive(Copy, Clone)]
struct CheckConstVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    const_kind: Option<hir::ConstContext>,
}

impl<'tcx> CheckConstVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstVisitor { tcx, const_kind: None }
    }

    /// Emits an error when an unsupported expression is found in a const context.
    fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
        let features = self.tcx.features();
        let required_gates = expr.required_feature_gates();
        match required_gates {
            // Don't emit an error if the user has enabled the requisite feature gates.
            Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,

            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
            // corresponding feature gate. This encourages nightly users to use feature gates when
            // possible.
            None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
                self.tcx.sess.span_warn(span, "skipping const checks");
                return;
            }

            _ => {}
        }

        let const_kind = self
            .const_kind
            .expect("`const_check_violated` may only be called inside a const context");

        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());

        let required_gates = required_gates.unwrap_or(&[]);
        let missing_gates: Vec<_> =
            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();

        match missing_gates.as_slice() {
            &[] => struct_span_err!(self.tcx.sess, span, E0744, "{}", msg).emit(),

            // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
            // explain why their `while` loop is being rejected.
            &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => {
                feature_err(&self.tcx.sess.parse_sess, gate, span, &msg)
                    .note(
                        "`#![feature(const_loop)]` alone is not sufficient, \
                           since this loop expression contains an implicit conditional",
                    )
                    .emit();
            }

            &[missing_primary, ref missing_secondary @ ..] => {
                let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);

                // If multiple feature gates would be required to enable this expression, include
                // them as help messages. Don't emit a separate error for each missing feature gate.
                //
                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
                // is a pretty narrow case, however.
                if nightly_options::is_nightly_build() {
                    for gate in missing_secondary {
                        let note = format!(
                            "add `#![feature({})]` to the crate attributes to enable",
                            gate,
                        );
                        err.help(&note);
                    }
                }

                err.emit();
            }
        }
    }

    /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
    fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
        let parent_kind = self.const_kind;
        self.const_kind = kind;
        f(self);
        self.const_kind = parent_kind;
    }
}

impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
        let kind = Some(hir::ConstContext::Const);
        self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
    }

    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
        let owner = self.tcx.hir().body_owner_def_id(body.id());
        let kind = self.tcx.hir().body_const_context(owner);
        self.recurse_into(kind, |this| intravisit::walk_body(this, body));
    }

    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
        if self.const_kind.is_some() {
            if let hir::PatKind::Or { .. } = p.kind {
                self.const_check_violated(NonConstExpr::OrPattern, p.span);
            }
        }
        intravisit::walk_pat(self, p)
    }

    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
        match &e.kind {
            // Skip the following checks if we are not currently in a const context.
            _ if self.const_kind.is_none() => {}

            hir::ExprKind::Loop(_, _, source) => {
                self.const_check_violated(NonConstExpr::Loop(*source), e.span);
            }

            hir::ExprKind::Match(_, _, source) => {
                let non_const_expr = match source {
                    // These are handled by `ExprKind::Loop` above.
                    hir::MatchSource::WhileDesugar
                    | hir::MatchSource::WhileLetDesugar
                    | hir::MatchSource::ForLoopDesugar => None,

                    _ => Some(NonConstExpr::Match(*source)),
                };

                if let Some(expr) = non_const_expr {
                    self.const_check_violated(expr, e.span);
                }
            }

            _ => {}
        }

        intravisit::walk_expr(self, e);
    }
}
<commit_msg>HIR const-checking<commit_after>//! This pass checks HIR bodies that may be evaluated at compile-time (e.g., `const`, `static`,
//! `const fn`) for structured control flow (e.g. `if`, `while`), which is forbidden in a const
//! context.
//!
//! By the time the MIR const-checker runs, these high-level constructs have been lowered to
//! control-flow primitives (e.g., `Goto`, `SwitchInt`), making it tough to properly attribute
//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
//! through, but errors for structured control flow in a `const` should be emitted here.

use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};

/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
    Loop(hir::LoopSource),
    Match(hir::MatchSource),
}

impl NonConstExpr {
    fn name(self) -> String {
        match self {
            Self::Loop(src) => format!("`{}`", src.name()),
            Self::Match(src) => format!("`{}`", src.name()),
        }
    }

    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
        use hir::LoopSource::*;
        use hir::MatchSource::*;

        let gates: &[_] = match self {
            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
            // so they are not yet allowed with `#![feature(const_loop)]`.
            // Likewise, `?` desugars to a call to `Try::into_result`.
            Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
                return None;
            }

            Self::Loop(Loop | While | WhileLet) | Self::Match(WhileDesugar | WhileLetDesugar) => {
                &[sym::const_loop]
            }

            // All other matches are allowed.
            Self::Match(Normal | IfDesugar { .. } | IfLetDesugar { .. }) => &[],
        };

        Some(gates)
    }
}

fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    let mut vis = CheckConstVisitor::new(tcx);
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
}

pub(crate) fn provide(providers: &mut Providers<'_>) {
    *providers = Providers { check_mod_const_bodies, ..*providers };
}

#[derive(Copy, Clone)]
struct CheckConstVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    const_kind: Option<hir::ConstContext>,
}

impl<'tcx> CheckConstVisitor<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        CheckConstVisitor { tcx, const_kind: None }
    }

    /// Emits an error when an unsupported expression is found in a const context.
    fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
        let features = self.tcx.features();
        let required_gates = expr.required_feature_gates();
        match required_gates {
            // Don't emit an error if the user has enabled the requisite feature gates.
            Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,

            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
            // corresponding feature gate. This encourages nightly users to use feature gates when
            // possible.
            None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
                self.tcx.sess.span_warn(span, "skipping const checks");
                return;
            }

            _ => {}
        }

        let const_kind = self
            .const_kind
            .expect("`const_check_violated` may only be called inside a const context");

        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());

        let required_gates = required_gates.unwrap_or(&[]);
        let missing_gates: Vec<_> =
            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();

        match missing_gates.as_slice() {
            &[] => struct_span_err!(self.tcx.sess, span, E0744, "{}", msg).emit(),

            &[missing_primary, ref missing_secondary @ ..] => {
                let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);

                // If multiple feature gates would be required to enable this expression, include
                // them as help messages. Don't emit a separate error for each missing feature gate.
                //
                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
                // is a pretty narrow case, however.
                if nightly_options::is_nightly_build() {
                    for gate in missing_secondary {
                        let note = format!(
                            "add `#![feature({})]` to the crate attributes to enable",
                            gate,
                        );
                        err.help(&note);
                    }
                }

                err.emit();
            }
        }
    }

    /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
    fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
        let parent_kind = self.const_kind;
        self.const_kind = kind;
        f(self);
        self.const_kind = parent_kind;
    }
}

impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
        let kind = Some(hir::ConstContext::Const);
        self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
    }

    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
        let owner = self.tcx.hir().body_owner_def_id(body.id());
        let kind = self.tcx.hir().body_const_context(owner);
        self.recurse_into(kind, |this| intravisit::walk_body(this, body));
    }

    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
        match &e.kind {
            // Skip the following checks if we are not currently in a const context.
            _ if self.const_kind.is_none() => {}

            hir::ExprKind::Loop(_, _, source) => {
                self.const_check_violated(NonConstExpr::Loop(*source), e.span);
            }

            hir::ExprKind::Match(_, _, source) => {
                let non_const_expr = match source {
                    // These are handled by `ExprKind::Loop` above.
                    hir::MatchSource::WhileDesugar
                    | hir::MatchSource::WhileLetDesugar
                    | hir::MatchSource::ForLoopDesugar => None,

                    _ => Some(NonConstExpr::Match(*source)),
                };

                if let Some(expr) = non_const_expr {
                    self.const_check_violated(expr, e.span);
                }
            }

            _ => {}
        }

        intravisit::walk_expr(self, e);
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate rusqlite;

use common::bookmark::Bookmark;
use dao::query_parser::*;
use self::rusqlite::Connection;
use std::path::Path;
use std::str::FromStr;
use self::chrono::*;

#[derive(Debug)]
pub struct BookmarkDao {
    connection: rusqlite::Connection,
    read_sql: String,
    delete_sql: String,
    insert_sql: String,
    update_sql: String,
    list_sql: String
}

impl BookmarkDao {
    pub fn new() -> BookmarkDao {
        BookmarkDao {
            connection: Connection::open(Path::new("res/BOOKMARKT.db")).unwrap(),
            read_sql: load_sql_file("res/sql/bookmark/read.sql"),
            delete_sql: load_sql_file("res/sql/bookmark/delete.sql"),
            insert_sql: load_sql_file("res/sql/bookmark/insert.sql"),
            update_sql: load_sql_file("res/sql/bookmark/update.sql"),
            list_sql: load_sql_file("res/sql/bookmark/list.sql")
        }
    }

    pub fn insert(&self, b: Bookmark) {
        let insert_query = parse_query(&b.to_btree(), String::from(&*self.insert_sql));

        match self.connection.execute(insert_query.as_str(), &[] ) {
            Ok(insert) => panic!("{} rows were inserted", insert),
            Err(err) => panic!("insert failed: {}", err),
        }
    }

    pub fn delete(&self, b: Bookmark) {
        let delete_query = parse_query(&b.to_btree(), String::from(&*self.delete_sql));

        match self.connection.execute(delete_query.as_str(), &[] ) {
            Ok(delete) => panic!("{} row was deleted", delete),
            Err(err) => panic!("delete failed: {}", err),
        }
    }

    pub fn read(&self, b: Bookmark) -> Result<Bookmark, rusqlite::Error> {
        let read_query = parse_query(&b.to_btree(), String::from(&*self.read_sql));

        let mut stmt = match self.connection.prepare(read_query.as_str()) {
            Ok(read) => read,
            Err(err) => panic!("delete failed: {}", err),
        };

        let bookmark_iter = stmt.query_map(&[], |row| {
            let time_dump: String = row.get(3);
            let stamp_dump: String = row.get(4);

            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                time_created: DateTime::<Local>::from_str(time_dump.as_str()).unwrap(),
                stamp: DateTime::<Local>::from_str(stamp_dump.as_str()).unwrap(),
                rev_no: row.get(5)
            }
        }).unwrap();

        bookmark_iter.last().expect("read failed !")
    }

    pub fn update(&self, b: Bookmark) {
        let update_query = parse_query(&b.to_btree(), String::from(&*self.update_sql));

        match self.connection.execute(update_query.as_str(), &[] ) {
            Ok(update) => update,
            Err(err) => panic!("listed failed: {}", err),
        };

    }

    pub fn list(&self, b: Bookmark) -> &[Bookmark] {
        let list_bookmark = Vec::new();
        let list_query = parse_query(&b.to_btree(), String::from(&*self.list_sql));

         let query_result = match self.connection.prepare(list_query.as_str()) {
            Ok(list) => list,
            Err(err) => panic!("listed failed: {}", err),
        };

        let mut bookmark_iter = query_result.query_map(&[], |row| {
            let time_dump: String = row.get(3);
            let stamp_dump: String = row.get(4);

            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                time_created: DateTime::<Local>::from_str(time_dump.as_str()).unwrap(),
                stamp: DateTime::<Local>::from_str(stamp_dump.as_str()).unwrap(),
                rev_no: row.get(5)
            }
        }).unwrap();

        for bookmark in bookmark_iter {
            list_bookmark.push(bookmark);
        }

        list_bookmark as &[Bookmark]
    }
}

pub fn hello_from_dao() -> String {
    "Hello, I am bookmark dao!".to_string()
}
<commit_msg>finish list for dao<commit_after>extern crate chrono;
extern crate rusqlite;

use common::bookmark::Bookmark;
use dao::query_parser::*;
use self::rusqlite::Connection;
use std::path::Path;
use std::str::FromStr;
use self::chrono::*;

#[derive(Debug)]
pub struct BookmarkDao {
    connection: rusqlite::Connection,
    read_sql: String,
    delete_sql: String,
    insert_sql: String,
    update_sql: String,
    list_sql: String
}

impl BookmarkDao {
    pub fn new() -> BookmarkDao {
        BookmarkDao {
            connection: Connection::open(Path::new("res/BOOKMARKT.db")).unwrap(),
            read_sql: load_sql_file("res/sql/bookmark/read.sql"),
            delete_sql: load_sql_file("res/sql/bookmark/delete.sql"),
            insert_sql: load_sql_file("res/sql/bookmark/insert.sql"),
            update_sql: load_sql_file("res/sql/bookmark/update.sql"),
            list_sql: load_sql_file("res/sql/bookmark/list.sql")
        }
    }

    pub fn insert(&self, b: Bookmark) {
        let insert_query = parse_query(&b.to_btree(), String::from(&*self.insert_sql));

        match self.connection.execute(insert_query.as_str(), &[] ) {
            Ok(insert) => panic!("{} rows were inserted", insert),
            Err(err) => panic!("insert failed: {}", err),
        }
    }

    pub fn delete(&self, b: Bookmark) {
        let delete_query = parse_query(&b.to_btree(), String::from(&*self.delete_sql));

        match self.connection.execute(delete_query.as_str(), &[] ) {
            Ok(delete) => panic!("{} row was deleted", delete),
            Err(err) => panic!("delete failed: {}", err),
        }
    }

    pub fn read(&self, b: Bookmark) -> Result<Bookmark, rusqlite::Error> {
        let read_query = parse_query(&b.to_btree(), String::from(&*self.read_sql));

        let mut stmt = match self.connection.prepare(read_query.as_str()) {
            Ok(read) => read,
            Err(err) => panic!("delete failed: {}", err),
        };

        let bookmark_iter = stmt.query_map(&[], |row| {
            let time_dump: String = row.get(3);
            let stamp_dump: String = row.get(4);

            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                time_created: DateTime::<Local>::from_str(time_dump.as_str()).unwrap(),
                stamp: DateTime::<Local>::from_str(stamp_dump.as_str()).unwrap(),
                rev_no: row.get(5)
            }
        }).unwrap();

        bookmark_iter.last().expect("read failed !")
    }

    pub fn update(&self, b: Bookmark) {
        let update_query = parse_query(&b.to_btree(), String::from(&*self.update_sql));

        match self.connection.execute(update_query.as_str(), &[] ) {
            Ok(update) => update,
            Err(err) => panic!("listed failed: {}", err),
        };

    }

    pub fn list(&self, b: Bookmark) -> Vec<Bookmark> {
        let mut list_bookmark = Vec::<Bookmark>::new();
        let list_query = parse_query(&b.to_btree(), String::from(&*self.list_sql));

         let mut query_result = match self.connection.prepare(list_query.as_str()) {
            Ok(list) => list,
            Err(err) => panic!("listed failed: {}", err),
        };

        let bookmark_iter = query_result.query_map(&[], |row| {
            let time_dump: String = row.get(3);
            let stamp_dump: String = row.get(4);

            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                time_created: DateTime::<Local>::from_str(time_dump.as_str()).unwrap(),
                stamp: DateTime::<Local>::from_str(stamp_dump.as_str()).unwrap(),
                rev_no: row.get(5)
            }
        }).unwrap();

        for result in bookmark_iter {
            match result {
                Ok(b) => list_bookmark.push(b),
                Err(_) => continue
            }
        }

        list_bookmark
    }
}

pub fn hello_from_dao() -> String {
    "Hello, I am bookmark dao!".to_string()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;
use std::num::SignedInt;

#[jstraceable]
#[deriving(Copy)]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Beginning of selection range with edit_point as end that can span multiple lines.
    selection_begin: Option<TextPoint>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

/// Was the keyboard event accompanied by the standard control modifier,
/// i.e. cmd on Mac OS or ctrl on other platforms.
#[cfg(target_os="macos")]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool {
    event.MetaKey() && !event.CtrlKey() && !event.AltKey()
}

#[cfg(not(target_os="macos"))]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool {
    event.CtrlKey() && !event.MetaKey() && !event.AltKey()
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            selection_begin: None,
            multiline: lines == Lines::Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        if self.selection_begin.is_none() {
            self.adjust_horizontal(if dir == DeleteDir::Forward {
                1
            } else {
                -1
            }, true);
        }
        self.replace_selection("".into_string());
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        if self.selection_begin.is_none() {
            self.selection_begin = Some(self.edit_point);
        }
        self.replace_selection(ch.to_string());
    }

    fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
        let begin = self.selection_begin.unwrap();
        let end = self.edit_point;

        if begin.line < end.line || (begin.line == end.line && begin.index < end.index) {
            (begin, end)
        } else {
            (end, begin)
        }
    }

    fn replace_selection(&mut self, insert: String) {
        let (begin, end) = self.get_sorted_selection();
        self.selection_begin = None;

        let new_lines = {
            let prefix = self.lines[begin.line].slice_chars(0, begin.index);
            let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].char_len());
            let lines_prefix = self.lines.slice(0, begin.line);
            let lines_suffix = self.lines.slice(end.line + 1, self.lines.len());

            let mut insert_lines = if self.multiline {
                insert.as_slice().split('\n').map(|s| s.into_string()).collect()
            } else {
                vec!(insert)
            };

            let mut new_line = prefix.into_string();
            new_line.push_str(insert_lines[0].as_slice());
            insert_lines[0] = new_line;

            let last_insert_lines_index = insert_lines.len() - 1;
            self.edit_point.index = insert_lines[last_insert_lines_index].char_len();
            self.edit_point.line = begin.line + last_insert_lines_index;

            insert_lines[last_insert_lines_index].push_str(suffix);

            let mut new_lines = vec!();
            new_lines.push_all(lines_prefix);
            new_lines.push_all(insert_lines.as_slice());
            new_lines.push_all(lines_suffix);
            new_lines
        };

        self.lines = new_lines;
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int, select: bool) {
        if !self.multiline {
            return;
        }

        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        assert!(self.edit_point.line < self.lines.len());

        let target_line: int = self.edit_point.line as int + adjust;

        if target_line < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if target_line as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = target_line as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int, select: bool) {
        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            if self.selection_begin.is_some() {
                let (begin, end) = self.get_sorted_selection();
                self.edit_point = if adjust < 0 {begin} else {end};
                self.selection_begin = None;
                return
            }
        }

        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1, select);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int + 1, select);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.lines.len() > self.edit_point.line + 1 {
                self.adjust_vertical(1, select);
                self.edit_point.index = 0;
                // one shift is consumed by the change of line, hence the -1
                self.adjust_horizontal(adjust - remaining as int - 1, select);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return KeyReaction::TriggerDefaultAction;
        }
        self.insert_char('\n');
        return KeyReaction::DispatchInput;
    }

    /// Select all text in the input control.
    fn select_all(&mut self) {
        self.selection_begin = Some(TextPoint {
            line: 0,
            index: 0,
        });
        let last_line = self.lines.len() - 1;
        self.edit_point.line = last_line;
        self.edit_point.index = self.lines[last_line].char_len();
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
           "a" if is_control_key(event) => {
                self.select_all();
                KeyReaction::Nothing
            },
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return KeyReaction::DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                KeyReaction::DispatchInput
            }
            "Delete" => {
                self.delete_char(DeleteDir::Forward);
                KeyReaction::DispatchInput
            }
            "Backspace" => {
                self.delete_char(DeleteDir::Backward);
                KeyReaction::DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1, event.ShiftKey());
                KeyReaction::Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1, event.ShiftKey());
                KeyReaction::Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1, event.ShiftKey());
                KeyReaction::Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1, event.ShiftKey());
                KeyReaction::Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                KeyReaction::Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                KeyReaction::Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28, event.ShiftKey());
                KeyReaction::Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28, event.ShiftKey());
                KeyReaction::Nothing
            }
            "Tab" => KeyReaction::TriggerDefaultAction,
            _ => KeyReaction::Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".into_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.into_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);

        if self.current_line_length() == 0 {
            self.edit_point.index = 0;
        }
        else {
            self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
        }
    }
}
<commit_msg>Fixes #4573 Replaces the boolean argument of TextInput::adjust[horizontal|vertical] with enum to self document the code<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;
use std::num::SignedInt;

#[deriving(Copy, PartialEq)]
enum Selection {
    Selected,
    NotSelected
}

#[jstraceable]
#[deriving(Copy)]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Beginning of selection range with edit_point as end that can span multiple lines.
    selection_begin: Option<TextPoint>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

/// Was the keyboard event accompanied by the standard control modifier,
/// i.e. cmd on Mac OS or ctrl on other platforms.
#[cfg(target_os="macos")]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool {
    event.MetaKey() && !event.CtrlKey() && !event.AltKey()
}

#[cfg(not(target_os="macos"))]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool {
    event.CtrlKey() && !event.MetaKey() && !event.AltKey()
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            selection_begin: None,
            multiline: lines == Lines::Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        if self.selection_begin.is_none() {
            self.adjust_horizontal(if dir == DeleteDir::Forward {
                1
            } else {
                -1
            }, Selection::Selected);
        }
        self.replace_selection("".into_string());
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        if self.selection_begin.is_none() {
            self.selection_begin = Some(self.edit_point);
        }
        self.replace_selection(ch.to_string());
    }

    fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
        let begin = self.selection_begin.unwrap();
        let end = self.edit_point;

        if begin.line < end.line || (begin.line == end.line && begin.index < end.index) {
            (begin, end)
        } else {
            (end, begin)
        }
    }

    fn replace_selection(&mut self, insert: String) {
        let (begin, end) = self.get_sorted_selection();
        self.selection_begin = None;

        let new_lines = {
            let prefix = self.lines[begin.line].slice_chars(0, begin.index);
            let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].char_len());
            let lines_prefix = self.lines.slice(0, begin.line);
            let lines_suffix = self.lines.slice(end.line + 1, self.lines.len());

            let mut insert_lines = if self.multiline {
                insert.as_slice().split('\n').map(|s| s.into_string()).collect()
            } else {
                vec!(insert)
            };

            let mut new_line = prefix.into_string();
            new_line.push_str(insert_lines[0].as_slice());
            insert_lines[0] = new_line;

            let last_insert_lines_index = insert_lines.len() - 1;
            self.edit_point.index = insert_lines[last_insert_lines_index].char_len();
            self.edit_point.line = begin.line + last_insert_lines_index;

            insert_lines[last_insert_lines_index].push_str(suffix);

            let mut new_lines = vec!();
            new_lines.push_all(lines_prefix);
            new_lines.push_all(insert_lines.as_slice());
            new_lines.push_all(lines_suffix);
            new_lines
        };

        self.lines = new_lines;
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int, select: Selection) {
        if !self.multiline {
            return;
        }

        if select == Selection::Selected {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        assert!(self.edit_point.line < self.lines.len());

        let target_line: int = self.edit_point.line as int + adjust;

        if target_line < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if target_line as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = target_line as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int, select: Selection) {
        if select == Selection::Selected {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            if self.selection_begin.is_some() {
                let (begin, end) = self.get_sorted_selection();
                self.edit_point = if adjust < 0 {begin} else {end};
                self.selection_begin = None;
                return
            }
        }

        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1, select);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int + 1, select);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.lines.len() > self.edit_point.line + 1 {
                self.adjust_vertical(1, select);
                self.edit_point.index = 0;
                // one shift is consumed by the change of line, hence the -1
                self.adjust_horizontal(adjust - remaining as int - 1, select);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return KeyReaction::TriggerDefaultAction;
        }
        self.insert_char('\n');
        return KeyReaction::DispatchInput;
    }

    /// Select all text in the input control.
    fn select_all(&mut self) {
        self.selection_begin = Some(TextPoint {
            line: 0,
            index: 0,
        });
        let last_line = self.lines.len() - 1;
        self.edit_point.line = last_line;
        self.edit_point.index = self.lines[last_line].char_len();
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        //A simple way to convert an event to a selection
        fn maybe_select(event: JSRef<KeyboardEvent>) -> Selection {
            if event.ShiftKey() {
                return Selection::Selected
            }
            return Selection::NotSelected
        }
        match event.Key().as_slice() {
           "a" if is_control_key(event) => {
                self.select_all();
                KeyReaction::Nothing
            },
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return KeyReaction::DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                KeyReaction::DispatchInput
            }
            "Delete" => {
                self.delete_char(DeleteDir::Forward);
                KeyReaction::DispatchInput
            }
            "Backspace" => {
                self.delete_char(DeleteDir::Backward);
                KeyReaction::DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1, maybe_select(event));
                KeyReaction::Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1, maybe_select(event));
                KeyReaction::Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1, maybe_select(event));
                KeyReaction::Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1, maybe_select(event));
                KeyReaction::Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                KeyReaction::Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                KeyReaction::Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28, maybe_select(event));
                KeyReaction::Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28, maybe_select(event));
                KeyReaction::Nothing
            }
            "Tab" => KeyReaction::TriggerDefaultAction,
            _ => KeyReaction::Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".into_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.into_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);

        if self.current_line_length() == 0 {
            self.edit_point.index = 0;
        }
        else {
            self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
        }
    }
}
<|endoftext|>