<commit_before>extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate tokio_process;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::io;
use std::process::{Stdio, ExitStatus, Command};

use futures::{Future, BoxFuture};
use futures::stream::{self, Stream};
use tokio_core::io::{read_until, write_all, read_to_end};
use tokio_core::reactor::Core;
use tokio_process::{CommandExt, Child};

mod support;

fn cat() -> Command {
    let mut cmd = support::cmd("cat");
    cmd.stdin(Stdio::piped())
       .stdout(Stdio::piped());
    cmd
}

fn feed_cat(mut cat: Child, n: usize) -> BoxFuture<ExitStatus, io::Error> {
    let stdin = cat.stdin().take().unwrap();
    let stdout = cat.stdout().take().unwrap();

    debug!("starting to feed");
    // Produce n lines on the child's stdout.
    let numbers = stream::iter((0..n).into_iter().map(Ok));
    let write = numbers.fold(stdin, |stdin, i| {
        debug!("sending line {} to child", i);
        write_all(stdin, format!("line {}\n", i).into_bytes()).map(|p| p.0)
    }).map(|_| ());

    // Try to read `n + 1` lines, ensuring the last one is empty
    // (i.e. EOF is reached after `n` lines.
    let reader = io::BufReader::new(stdout);
    let expected_numbers = stream::iter((0..n + 1).map(Ok));
    let read = expected_numbers.fold((reader, 0), move |(reader, i), _| {
        let done = i >= n;
        debug!("starting read from child");
        read_until(reader, b'\n', Vec::new()).and_then(move |(reader, vec)| {
            debug!("read line {} from child ({} bytes, done: {})",
                   i, vec.len(), done);
            match (done, vec.len()) {
                (false, 0) => {
                    Err(io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                },
                (true, n) if n != 0 => {
                    Err(io::Error::new(io::ErrorKind::Other, "extraneous data"))
                },
                _ => {
                    let s = std::str::from_utf8(&vec).unwrap();
                    let expected = format!("line {}\n", i);
                    if done || s == expected {
                        Ok((reader, i + 1))
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "unexpected data"))
                    }
                }
            }
        })
    });

    // Compose reading and writing concurrently.
    write.join(read).and_then(|_| cat).boxed()
}

#[test]
/// Check for the following properties when feeding stdin and
/// consuming stdout of a cat-like process:
///
/// - A number of lines that amounts to a number of bytes exceeding a
///   typical OS buffer size can be fed to the child without
///   deadlock. This tests that we also consume the stdout
///   concurrently; otherwise this would deadlock.
///
/// - We read the same lines from the child that we fed it.
///
/// - The child does produce EOF on stdout after the last line.
fn feed_a_lot() {
    support::init();

    let mut lp = Core::new().unwrap();
    let child = cat().spawn_async(&lp.handle()).unwrap();
    let status = lp.run(feed_cat(child, 10000)).unwrap();
    assert_eq!(status.code(), Some(0));
}

#[test]
fn drop_kills() {
    support::init();

    let mut lp = Core::new().unwrap();
    let mut child = cat().spawn_async(&lp.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let stdout = child.stdout().take().unwrap();
    drop(child);

    let (_, output) = lp.run(read_to_end(stdout, Vec::new())).unwrap();
    assert_eq!(output.len(), 0);
    let err = lp.run(write_all(stdin, b"1234")).err().unwrap();
    assert_eq!(err.kind(), io::ErrorKind::BrokenPipe);
}

#[test]
fn wait_with_output_captures() {
    support::init();

    let mut core = Core::new().unwrap();

    let mut child = cat().spawn_async(&core.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let out = child.wait_with_output();

    let ret = core.run(write_all(stdin, b"1234").map(|p| p.1).join(out)).unwrap();
    let (written, output) = ret;

    assert!(output.status.success());
    assert_eq!(output.stdout, written);
    assert_eq!(output.stderr.len(), 0);
}
<commit_msg>process: Tweak drop_kills test<commit_after>extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate tokio_process;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::io;
use std::process::{Stdio, ExitStatus, Command};

use futures::{Future, BoxFuture};
use futures::stream::{self, Stream};
use tokio_core::io::{read_until, write_all, read_to_end};
use tokio_core::reactor::Core;
use tokio_process::{CommandExt, Child};

mod support;

fn cat() -> Command {
    let mut cmd = support::cmd("cat");
    cmd.stdin(Stdio::piped())
       .stdout(Stdio::piped());
    cmd
}

fn feed_cat(mut cat: Child, n: usize) -> BoxFuture<ExitStatus, io::Error> {
    let stdin = cat.stdin().take().unwrap();
    let stdout = cat.stdout().take().unwrap();

    debug!("starting to feed");
    // Produce n lines on the child's stdout.
    let numbers = stream::iter((0..n).into_iter().map(Ok));
    let write = numbers.fold(stdin, |stdin, i| {
        debug!("sending line {} to child", i);
        write_all(stdin, format!("line {}\n", i).into_bytes()).map(|p| p.0)
    }).map(|_| ());

    // Try to read `n + 1` lines, ensuring the last one is empty
    // (i.e. EOF is reached after `n` lines.
    let reader = io::BufReader::new(stdout);
    let expected_numbers = stream::iter((0..n + 1).map(Ok));
    let read = expected_numbers.fold((reader, 0), move |(reader, i), _| {
        let done = i >= n;
        debug!("starting read from child");
        read_until(reader, b'\n', Vec::new()).and_then(move |(reader, vec)| {
            debug!("read line {} from child ({} bytes, done: {})",
                   i, vec.len(), done);
            match (done, vec.len()) {
                (false, 0) => {
                    Err(io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                },
                (true, n) if n != 0 => {
                    Err(io::Error::new(io::ErrorKind::Other, "extraneous data"))
                },
                _ => {
                    let s = std::str::from_utf8(&vec).unwrap();
                    let expected = format!("line {}\n", i);
                    if done || s == expected {
                        Ok((reader, i + 1))
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "unexpected data"))
                    }
                }
            }
        })
    });

    // Compose reading and writing concurrently.
    write.join(read).and_then(|_| cat).boxed()
}

#[test]
/// Check for the following properties when feeding stdin and
/// consuming stdout of a cat-like process:
///
/// - A number of lines that amounts to a number of bytes exceeding a
///   typical OS buffer size can be fed to the child without
///   deadlock. This tests that we also consume the stdout
///   concurrently; otherwise this would deadlock.
///
/// - We read the same lines from the child that we fed it.
///
/// - The child does produce EOF on stdout after the last line.
fn feed_a_lot() {
    support::init();

    let mut lp = Core::new().unwrap();
    let child = cat().spawn_async(&lp.handle()).unwrap();
    let status = lp.run(feed_cat(child, 10000)).unwrap();
    assert_eq!(status.code(), Some(0));
}

#[test]
fn drop_kills() {
    support::init();

    let mut lp = Core::new().unwrap();
    let mut child = cat().spawn_async(&lp.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let stdout = child.stdout().take().unwrap();
    drop(child);

    drop(lp.run(write_all(stdin, b"1234")));
    let (_, output) = lp.run(read_to_end(stdout, Vec::new())).unwrap();
    assert_eq!(output.len(), 0);
}

#[test]
fn wait_with_output_captures() {
    support::init();

    let mut core = Core::new().unwrap();

    let mut child = cat().spawn_async(&core.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let out = child.wait_with_output();

    let ret = core.run(write_all(stdin, b"1234").map(|p| p.1).join(out)).unwrap();
    let (written, output) = ret;

    assert!(output.status.success());
    assert_eq!(output.stdout, written);
    assert_eq!(output.stderr.len(), 0);
}
<|endoftext|>


<commit_before>//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

/// A trait for borrowing data.
///
/// In Rust, it is common to provide different representations of a type for
/// different use cases. For instance, storage location and management for a
/// value can be specifically chosen as appropriate for a particular use via
/// pointer types such as [`Box<T>`] or [`Rc<T>`]. Beyond these generic
/// wrappers that can be used with any type, some types provide optional
/// facets providing potentially costly functionality. An example for such a
/// type is [`String`] which adds the ability to extend a string to the basic
/// [`str`]. This requires keeping additional information unnecessary for a
/// simple, immutable string.
///
/// These types provide access to the underlying data through references
/// to the type of that data. They are said to be ‘borrowed as’ that type.
/// For instance, a [`Box<T>`] can be borrowed as `T` while a [`String`]
/// can be borrowed as `str`.
///
/// Types express that they can be borrowed as some type `T` by implementing
/// `Borrow<T>`, providing a reference to a `T` in the trait’s
/// [`borrow`] method. A type is free to borrow as several different types.
/// If it wishes to mutably borrow as the type – allowing the underlying data
/// to be modified, it can additionally implement [`BorrowMut<T>`].
///
/// Further, when providing implementations for additional traits, it needs
/// to be considered whether they should behave identical to those of the
/// underlying type as a consequence of acting as a representation of that
/// underlying type. Generic code typically uses `Borrow<T>` when it relies
/// on the identical behavior of these additional trait implementations.
/// These traits will likely appear as additional trait bounds.
///
/// In particular `Eq`, `Ord` and `Hash` must be equivalent for
/// borrowed and owned values: `x.borrow() == y.borrow()` should give the
/// same result as `x == y`.
///
/// If generic code merely needs to work for all types that can
/// provide a reference to related type `T`, it is often better to use
/// [`AsRef<T>`] as more types can safely implement it.
///
/// [`AsRef<T>`]: crate::convert::AsRef
/// [`BorrowMut<T>`]: BorrowMut
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
/// [`Mutex<T>`]: ../../std/sync/struct.Mutex.html
/// [`Rc<T>`]: ../../std/rc/struct.Rc.html
/// [`String`]: ../../std/string/struct.String.html
/// [`borrow`]: Borrow::borrow
///
/// # Examples
///
/// As a data collection, [`HashMap<K, V>`] owns both keys and values. If
/// the key’s actual data is wrapped in a managing type of some kind, it
/// should, however, still be possible to search for a value using a
/// reference to the key’s data. For instance, if the key is a string, then
/// it is likely stored with the hash map as a [`String`], while it should
/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to
/// operate on a `String` while `get` needs to be able to use a `&str`.
///
/// Slightly simplified, the relevant parts of `HashMap<K, V>` look like
/// this:
///
/// ```
/// use std::borrow::Borrow;
/// use std::hash::Hash;
///
/// pub struct HashMap<K, V> {
///     # marker: ::std::marker::PhantomData<(K, V)>,
///     // fields omitted
/// }
///
/// impl<K, V> HashMap<K, V> {
///     pub fn insert(&self, key: K, value: V) -> Option<V>
///     where K: Hash + Eq
///     {
///         # unimplemented!()
///         // ...
///     }
///
///     pub fn get<Q>(&self, k: &Q) -> Option<&V>
///     where
///         K: Borrow<Q>,
///         Q: Hash + Eq + ?Sized
///     {
///         # unimplemented!()
///         // ...
///     }
/// }
/// ```
///
/// The entire hash map is generic over a key type `K`. Because these keys
/// are stored with the hash map, this type has to own the key’s data.
/// When inserting a key-value pair, the map is given such a `K` and needs
/// to find the correct hash bucket and check if the key is already present
/// based on that `K`. It therefore requires `K: Hash + Eq`.
///
/// When searching for a value in the map, however, having to provide a
/// reference to a `K` as the key to search for would require to always
/// create such an owned value. For string keys, this would mean a `String`
/// value needs to be created just for the search for cases where only a
/// `str` is available.
///
/// Instead, the `get` method is generic over the type of the underlying key
/// data, called `Q` in the method signature above. It states that `K`
/// borrows as a `Q` by requiring that `K: Borrow<Q>`. By additionally
/// requiring `Q: Hash + Eq`, it signals the requirement that `K` and `Q`
/// have implementations of the `Hash` and `Eq` traits that produce identical
/// results.
///
/// The implementation of `get` relies in particular on identical
/// implementations of `Hash` by determining the key’s hash bucket by calling
/// `Hash::hash` on the `Q` value even though it inserted the key based on
/// the hash value calculated from the `K` value.
///
/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
/// produces a different hash than `Q`. For instance, imagine you have a
/// type that wraps a string but compares ASCII letters ignoring their case:
///
/// ```
/// pub struct CaseInsensitiveString(String);
///
/// impl PartialEq for CaseInsensitiveString {
///     fn eq(&self, other: &Self) -> bool {
///         self.0.eq_ignore_ascii_case(&other.0)
///     }
/// }
///
/// impl Eq for CaseInsensitiveString { }
/// ```
///
/// Because two equal values need to produce the same hash value, the
/// implementation of `Hash` needs to ignore ASCII case, too:
///
/// ```
/// # use std::hash::{Hash, Hasher};
/// # pub struct CaseInsensitiveString(String);
/// impl Hash for CaseInsensitiveString {
///     fn hash<H: Hasher>(&self, state: &mut H) {
///         for c in self.0.as_bytes() {
///             c.to_ascii_lowercase().hash(state)
///         }
///     }
/// }
/// ```
///
/// Can `CaseInsensitiveString` implement `Borrow<str>`? It certainly can
/// provide a reference to a string slice via its contained owned string.
/// But because its `Hash` implementation differs, it behaves differently
/// from `str` and therefore must not, in fact, implement `Borrow<str>`.
/// If it wants to allow others access to the underlying `str`, it can do
/// that via `AsRef<str>` which doesn’t carry any extra requirements.
///
/// [`Hash`]: crate::hash::Hash
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
/// [`String`]: ../../std/string/struct.String.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::Borrow;
    ///
    /// fn check<T: Borrow<str>>(s: T) {
    ///     assert_eq!("Hello", s.borrow());
    /// }
    ///
    /// let s = "Hello".to_string();
    ///
    /// check(s);
    ///
    /// let s = "Hello";
    ///
    /// check(s);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// As a companion to [`Borrow<T>`] this trait allows a type to borrow as
/// an underlying type by providing a mutable reference. See [`Borrow<T>`]
/// for more information on borrowing as another type.
///
/// [`Borrow<T>`]: Borrow
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
    /// Mutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::BorrowMut;
    ///
    /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
    ///     assert_eq!(&mut [1, 2, 3], v.borrow_mut());
    /// }
    ///
    /// let v = vec![1, 2, 3];
    ///
    /// check(v);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &T {
    fn borrow(&self) -> &T {
        &**self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &mut T {
    fn borrow(&self) -> &T {
        &**self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for &mut T {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}
<commit_msg>Remove AsRef link as it is in the prelude<commit_after>//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

/// A trait for borrowing data.
///
/// In Rust, it is common to provide different representations of a type for
/// different use cases. For instance, storage location and management for a
/// value can be specifically chosen as appropriate for a particular use via
/// pointer types such as [`Box<T>`] or [`Rc<T>`]. Beyond these generic
/// wrappers that can be used with any type, some types provide optional
/// facets providing potentially costly functionality. An example for such a
/// type is [`String`] which adds the ability to extend a string to the basic
/// [`str`]. This requires keeping additional information unnecessary for a
/// simple, immutable string.
///
/// These types provide access to the underlying data through references
/// to the type of that data. They are said to be ‘borrowed as’ that type.
/// For instance, a [`Box<T>`] can be borrowed as `T` while a [`String`]
/// can be borrowed as `str`.
///
/// Types express that they can be borrowed as some type `T` by implementing
/// `Borrow<T>`, providing a reference to a `T` in the trait’s
/// [`borrow`] method. A type is free to borrow as several different types.
/// If it wishes to mutably borrow as the type – allowing the underlying data
/// to be modified, it can additionally implement [`BorrowMut<T>`].
///
/// Further, when providing implementations for additional traits, it needs
/// to be considered whether they should behave identical to those of the
/// underlying type as a consequence of acting as a representation of that
/// underlying type. Generic code typically uses `Borrow<T>` when it relies
/// on the identical behavior of these additional trait implementations.
/// These traits will likely appear as additional trait bounds.
///
/// In particular `Eq`, `Ord` and `Hash` must be equivalent for
/// borrowed and owned values: `x.borrow() == y.borrow()` should give the
/// same result as `x == y`.
///
/// If generic code merely needs to work for all types that can
/// provide a reference to related type `T`, it is often better to use
/// [`AsRef<T>`] as more types can safely implement it.
///
/// [`BorrowMut<T>`]: BorrowMut
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
/// [`Mutex<T>`]: ../../std/sync/struct.Mutex.html
/// [`Rc<T>`]: ../../std/rc/struct.Rc.html
/// [`String`]: ../../std/string/struct.String.html
/// [`borrow`]: Borrow::borrow
///
/// # Examples
///
/// As a data collection, [`HashMap<K, V>`] owns both keys and values. If
/// the key’s actual data is wrapped in a managing type of some kind, it
/// should, however, still be possible to search for a value using a
/// reference to the key’s data. For instance, if the key is a string, then
/// it is likely stored with the hash map as a [`String`], while it should
/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to
/// operate on a `String` while `get` needs to be able to use a `&str`.
///
/// Slightly simplified, the relevant parts of `HashMap<K, V>` look like
/// this:
///
/// ```
/// use std::borrow::Borrow;
/// use std::hash::Hash;
///
/// pub struct HashMap<K, V> {
///     # marker: ::std::marker::PhantomData<(K, V)>,
///     // fields omitted
/// }
///
/// impl<K, V> HashMap<K, V> {
///     pub fn insert(&self, key: K, value: V) -> Option<V>
///     where K: Hash + Eq
///     {
///         # unimplemented!()
///         // ...
///     }
///
///     pub fn get<Q>(&self, k: &Q) -> Option<&V>
///     where
///         K: Borrow<Q>,
///         Q: Hash + Eq + ?Sized
///     {
///         # unimplemented!()
///         // ...
///     }
/// }
/// ```
///
/// The entire hash map is generic over a key type `K`. Because these keys
/// are stored with the hash map, this type has to own the key’s data.
/// When inserting a key-value pair, the map is given such a `K` and needs
/// to find the correct hash bucket and check if the key is already present
/// based on that `K`. It therefore requires `K: Hash + Eq`.
///
/// When searching for a value in the map, however, having to provide a
/// reference to a `K` as the key to search for would require to always
/// create such an owned value. For string keys, this would mean a `String`
/// value needs to be created just for the search for cases where only a
/// `str` is available.
///
/// Instead, the `get` method is generic over the type of the underlying key
/// data, called `Q` in the method signature above. It states that `K`
/// borrows as a `Q` by requiring that `K: Borrow<Q>`. By additionally
/// requiring `Q: Hash + Eq`, it signals the requirement that `K` and `Q`
/// have implementations of the `Hash` and `Eq` traits that produce identical
/// results.
///
/// The implementation of `get` relies in particular on identical
/// implementations of `Hash` by determining the key’s hash bucket by calling
/// `Hash::hash` on the `Q` value even though it inserted the key based on
/// the hash value calculated from the `K` value.
///
/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
/// produces a different hash than `Q`. For instance, imagine you have a
/// type that wraps a string but compares ASCII letters ignoring their case:
///
/// ```
/// pub struct CaseInsensitiveString(String);
///
/// impl PartialEq for CaseInsensitiveString {
///     fn eq(&self, other: &Self) -> bool {
///         self.0.eq_ignore_ascii_case(&other.0)
///     }
/// }
///
/// impl Eq for CaseInsensitiveString { }
/// ```
///
/// Because two equal values need to produce the same hash value, the
/// implementation of `Hash` needs to ignore ASCII case, too:
///
/// ```
/// # use std::hash::{Hash, Hasher};
/// # pub struct CaseInsensitiveString(String);
/// impl Hash for CaseInsensitiveString {
///     fn hash<H: Hasher>(&self, state: &mut H) {
///         for c in self.0.as_bytes() {
///             c.to_ascii_lowercase().hash(state)
///         }
///     }
/// }
/// ```
///
/// Can `CaseInsensitiveString` implement `Borrow<str>`? It certainly can
/// provide a reference to a string slice via its contained owned string.
/// But because its `Hash` implementation differs, it behaves differently
/// from `str` and therefore must not, in fact, implement `Borrow<str>`.
/// If it wants to allow others access to the underlying `str`, it can do
/// that via `AsRef<str>` which doesn’t carry any extra requirements.
///
/// [`Hash`]: crate::hash::Hash
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
/// [`String`]: ../../std/string/struct.String.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::Borrow;
    ///
    /// fn check<T: Borrow<str>>(s: T) {
    ///     assert_eq!("Hello", s.borrow());
    /// }
    ///
    /// let s = "Hello".to_string();
    ///
    /// check(s);
    ///
    /// let s = "Hello";
    ///
    /// check(s);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// As a companion to [`Borrow<T>`] this trait allows a type to borrow as
/// an underlying type by providing a mutable reference. See [`Borrow<T>`]
/// for more information on borrowing as another type.
///
/// [`Borrow<T>`]: Borrow
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
    /// Mutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::BorrowMut;
    ///
    /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
    ///     assert_eq!(&mut [1, 2, 3], v.borrow_mut());
    /// }
    ///
    /// let v = vec![1, 2, 3];
    ///
    /// check(v);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &T {
    fn borrow(&self) -> &T {
        &**self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for &mut T {
    fn borrow(&self) -> &T {
        &**self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for &mut T {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}
<|endoftext|>


<commit_before>use runtime::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::FunctionName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::FunctionName {
    ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the runtime data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
/// essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the runtime data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the runtime data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the DummyEnvironment.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl ModuleEnvironment for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import<'data>(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: &[FunctionIndex],
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization<'data>(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export<'data>(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export<'data>(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export<'data>(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export<'data>(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    /// Provides the contents of a function body.
    fn define_function_body<'data>(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<commit_msg>Minor comment cleanup.<commit_after>use runtime::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::FunctionName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::FunctionName {
    ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the runtime data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
/// essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the runtime data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the runtime data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl ModuleEnvironment for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import<'data>(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: &[FunctionIndex],
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization<'data>(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export<'data>(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export<'data>(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export<'data>(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export<'data>(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    /// Provides the contents of a function body.
    fn define_function_body<'data>(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagstore::store::Entry;

use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;

use error::Result;
use error::NoteErrorKind as NEK;
use error::NoteError as NE;
use error::ResultExt;

pub trait Note {
    fn set_name(&mut self, n: String) -> Result<()>;
    fn get_name(&self) -> Result<String>;
    fn set_text(&mut self, n: String);
    fn get_text(&self) -> &String;
}

impl Note for Entry {

    fn set_name(&mut self, n: String) -> Result<()> {
        self.get_header_mut()
            .set("note.name", Value::String(n))
            .chain_err(|| NEK::StoreWriteError)
            .map(|_| ())
    }

    fn get_name(&self) -> Result<String> {
        match self.get_header().read("note.name") {
            Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
            Ok(_) => {
                Err(NE::from_kind(NEK::HeaderTypeError)).chain_err(|| NEK::StoreReadError)
            },
            Err(e) => Err(e).chain_err(|| NEK::StoreReadError)
        }
    }

    fn set_text(&mut self, n: String) {
        *self.get_content_mut() = n
    }

    fn get_text(&self) -> &String {
        self.get_content()
    }

}

<commit_msg>Refactoring: Use function chaining rather than matching<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagstore::store::Entry;

use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;

use error::Result;
use error::NoteErrorKind as NEK;
use error::NoteError as NE;
use error::ResultExt;

pub trait Note {
    fn set_name(&mut self, n: String) -> Result<()>;
    fn get_name(&self) -> Result<String>;
    fn set_text(&mut self, n: String);
    fn get_text(&self) -> &String;
}

impl Note for Entry {

    fn set_name(&mut self, n: String) -> Result<()> {
        self.get_header_mut()
            .set("note.name", Value::String(n))
            .chain_err(|| NEK::StoreWriteError)
            .map(|_| ())
    }

    fn get_name(&self) -> Result<String> {
        self.get_header()
            .read("note.name")
            .chain_err(|| NEK::StoreReadError)?
            .and_then(Value::as_str)
            .map(String::from)
            .ok_or(NE::from_kind(NEK::HeaderTypeError))
    }

    fn set_text(&mut self, n: String) {
        *self.get_content_mut() = n
    }

    fn get_text(&self) -> &String {
        self.get_content()
    }

}

<|endoftext|>


<commit_before>use std::char;
use std::cell::Cell;
use std::fmt;

pub struct Lexer {
    input: String,
    position: Cell<usize>,
    read_position: Cell<usize>,
    ch: Cell<char>
}

impl Lexer {
    pub fn new(input: String) -> Lexer {
        let l = Lexer {
            input: input,
            position: Cell::new(0),
            read_position: Cell::new(0),
            ch: Cell::new(' ')
        };
        l.read_char();
        return l;
    }

    pub fn read_char(&self) {
        if self.read_position.get() >= self.input.len() {
            self.ch.set('\0');
        } else {
            let c = self.input.chars().nth(self.read_position.get()).unwrap();
            self.ch.set(c);
        }
        self.position.set(self.read_position.get());
        self.read_position.set(self.read_position.get() + 1);
    }

    pub fn next_token(&self) -> Token {
        self.skip_white_space();
        let ch = self.ch.get();
        self.get_token(ch)
    }

    pub fn get_token(&self, s: char) -> Token {
        let token = match s {
            '=' => {
                if self.peek_char() == '=' {
                    self.read_char();
                    Token {
                        token_type: TokenType::Eq,
                        value: Some(Value::Str(String::from("=="))) // TODO: 文字列を連結するように修正する
                    }
                } else {
                    Token {
                        token_type: TokenType::Assign,
                        value: Some(Value::Str(String::from("=")))
                    }
                }
            }
            '+' => {
                Token {
                    token_type: TokenType::Plus,
                    value: Some(Value::Str(String::from("+")))
                }
            }
            '-' => {
                Token {
                    token_type: TokenType::Minus,
                    value: Some(Value::Str(String::from("-")))
                }
            }
            '!' => {
                if self.peek_char() == '=' {
                    self.read_char();
                    Token {
                        token_type: TokenType::NotEq,
                        value: Some(Value::Str(String::from("!=")))
                    }
                } else {
                    Token {
                        token_type: TokenType::Bang,
                        value: Some(Value::Str(String::from("!")))
                    }
                }
            }
            '/' => {
                Token {
                    token_type: TokenType::Slash,
                    value: Some(Value::Str(String::from("/")))
                }
            }
            '*' => {
                Token {
                    token_type: TokenType::Asterisk,
                    value: Some(Value::Str(String::from("*")))
                }
            }
            '<' => {
                Token {
                    token_type: TokenType::Lt,
                    value: Some(Value::Str(String::from("<")))
                }
            }
            '>' => {
                Token {
                    token_type: TokenType::Gt,
                    value: Some(Value::Str(String::from(">")))
                }
            }
            ';' => {
                Token {
                    token_type: TokenType::Semicolon,
                    value: Some(Value::Str(String::from(";")))
                }
            }
            '(' => {
                Token {
                    token_type: TokenType::Lparen,
                    value: Some(Value::Str(String::from("(")))
                }
            }
            ')' => {
                Token {
                    token_type: TokenType::Rparen,
                    value: Some(Value::Str(String::from(")")))
                }
            }
            ',' => {
                Token {
                    token_type: TokenType::Comma,
                    value: Some(Value::Str(String::from(",")))
                }
            }
            '{' => {
                Token {
                    token_type: TokenType::LBRACE,
                    value: Some(Value::Str(String::from("{")))
                }
            }
            '}' => {
                Token {
                    token_type: TokenType::Rbrace,
                    value: Some(Value::Str(String::from("}")))
                }
            }
            '\0' => {
                Token {
                    token_type: TokenType::Eof,
                    value: Some(Value::Str(String::from("\0")))
                }
            }
            c => {
                if is_letter(c) {
                    let identifier = unsafe {self.read_identifier()};
                    Token {
                        token_type: unsafe {self.lookup_ident(&identifier)},
                        value: Some(Value::Str(identifier))
                    }
                } else if is_digit(c) {
                    Token {
                        token_type: TokenType::Int,
                        value: Some(Value::Str(unsafe { self.read_number()}))
                    }
                } else {
                    Token {
                        token_type: TokenType::Illegal,
                        value: None
                    }
                }
            }
        };
        self.read_char();
        return token;
    }

    pub unsafe fn read_identifier(&self) -> String {
        let start_position = self.position.get();
        while is_letter(self.ch.get()) {
            self.read_char();
        }
        let end_position = self.position.get();
        let s = self.input.slice_unchecked(start_position, end_position);
        s.to_string()
    }

    pub unsafe fn lookup_ident(&self, s: &str) -> TokenType {
        match s {
            "fn" => TokenType::Function,
            "let" => TokenType::Let,
            "true" => TokenType::True,
            "false" => TokenType::False,
            "if" => TokenType::If,
            "else" => TokenType::Else,
            "return" => TokenType::Return,
            _ => TokenType::Ident
        }
    }

    pub unsafe fn read_number(&self) -> String {
        let start_position = self.position.get();
        while is_digit(self.ch.get()) {
            self.read_char();
        }
        let end_position = self.position.get();
        let s = self.input.slice_unchecked(start_position, end_position);
        return s.to_string();
    }

    pub fn skip_white_space(&self) {
        let ch = self.ch.get();
        while ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' {
            self.read_char();
        }
    }

    pub fn peek_char(&self) -> char {
        if self.read_position.get() >= self.input.len() {
            return '0';
        } else {
            return self.input.chars().nth(self.read_position.get()).unwrap();
        }
    }
}

fn is_letter(ch: char) -> bool {
    return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_';
}

fn is_digit(ch: char) -> bool {
    return '0' <= ch && ch <= '9';
}

#[derive(Debug)]
pub enum Value {
    Str(String),
}

#[derive(Debug, PartialEq)]
pub enum TokenType {
    Illegal,
    Eof,

    Ident,
    Int,

    Assign,
    Plus,
    Minus,
    Bang,
    Asterisk,
    Slash,
    Eq,
    NotEq,

    Lt,
    Gt,

    Comma,
    Semicolon,

    Lparen,
    Rparen,
    LBRACE,
    Rbrace,

    Function,
    Let,
    True,
    False,
    If,
    Else,
    Return
}

#[derive(Debug)]
pub struct Token {
    pub token_type: TokenType,
    pub value: Option<Value>,
}

impl fmt::Display for Token  {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", 1.0)
    }
}

// Test
#[test]
fn peek_char() {
    let input = String::from("!=");
    let l = &Lexer::new(input);
    assert_eq!('=', l.peek_char());
    assert_eq!('=', l.peek_char());
}

#[test]
fn next_token_base() {
    let input = String::from("=()");
    let l = &Lexer::new(input);
    assert_eq!(l.next_token().token_type, TokenType::Assign);
    assert_eq!(l.next_token().token_type, TokenType::Lparen);
    assert_eq!(l.next_token().token_type, TokenType::Rparen);
}

#[test]
fn test_is_digit() {
    assert_eq!(is_digit('0'), true);
    assert_eq!(is_digit('1'), true);
    assert_eq!(is_digit('8'), true);
    assert_eq!(is_digit('9'), true);
}

#[test]
fn test_is_letter() {
    assert_eq!(is_letter('_'), true);
    assert_eq!(is_letter('a'), true);
    assert_eq!(is_letter('b'), true);
    assert_eq!(is_letter('y'), true);
    assert_eq!(is_letter('z'), true);
    assert_eq!(is_letter('A'), true);
    assert_eq!(is_letter('B'), true);
    assert_eq!(is_letter('Y'), true);
    assert_eq!(is_letter('Z'), true);
}

#[test]
fn next_token() {
    let input = String::from("let five = 5;
let ten = 10;

let add = fn(x, y) {
    x + y;
};

let result = add(five, ten);
!-/*5;
5 < 10 > 5;

if (5 < 10) {
    return true;
} else {
    return false;
}

10 == 10;
10 != 9;");
    let l = &Lexer::new(input);
    assert_eq!(l.next_token().token_type, TokenType::Let);
    assert_eq!(l.next_token().token_type, TokenType::Ident);
    assert_eq!(l.next_token().token_type, TokenType::Assign);
    assert_eq!(l.next_token().token_type, TokenType::Int);
}
<commit_msg>delete return statement<commit_after>use std::char;
use std::cell::Cell;
use std::fmt;

pub struct Lexer {
    input: String,
    position: Cell<usize>,
    read_position: Cell<usize>,
    ch: Cell<char>
}

impl Lexer {
    pub fn new(input: String) -> Lexer {
        let l = Lexer {
            input: input,
            position: Cell::new(0),
            read_position: Cell::new(0),
            ch: Cell::new(' ')
        };
        l.read_char();
        l
    }

    pub fn read_char(&self) {
        if self.read_position.get() >= self.input.len() {
            self.ch.set('\0');
        } else {
            let c = self.input.chars().nth(self.read_position.get()).unwrap();
            self.ch.set(c);
        }
        self.position.set(self.read_position.get());
        self.read_position.set(self.read_position.get() + 1);
    }

    pub fn next_token(&self) -> Token {
        self.skip_white_space();
        self.get_token(self.ch.get())
    }

    pub fn get_token(&self, s: char) -> Token {
        let token = match s {
            '=' => {
                if self.peek_char() == '=' {
                    self.read_char();
                    Token {
                        token_type: TokenType::Eq,
                        value: Some(Value::Str(String::from("=="))) // TODO: 文字列を連結するように修正する
                    }
                } else {
                    Token {
                        token_type: TokenType::Assign,
                        value: Some(Value::Str(String::from("=")))
                    }
                }
            }
            '+' => {
                Token {
                    token_type: TokenType::Plus,
                    value: Some(Value::Str(String::from("+")))
                }
            }
            '-' => {
                Token {
                    token_type: TokenType::Minus,
                    value: Some(Value::Str(String::from("-")))
                }
            }
            '!' => {
                if self.peek_char() == '=' {
                    self.read_char();
                    Token {
                        token_type: TokenType::NotEq,
                        value: Some(Value::Str(String::from("!=")))
                    }
                } else {
                    Token {
                        token_type: TokenType::Bang,
                        value: Some(Value::Str(String::from("!")))
                    }
                }
            }
            '/' => {
                Token {
                    token_type: TokenType::Slash,
                    value: Some(Value::Str(String::from("/")))
                }
            }
            '*' => {
                Token {
                    token_type: TokenType::Asterisk,
                    value: Some(Value::Str(String::from("*")))
                }
            }
            '<' => {
                Token {
                    token_type: TokenType::Lt,
                    value: Some(Value::Str(String::from("<")))
                }
            }
            '>' => {
                Token {
                    token_type: TokenType::Gt,
                    value: Some(Value::Str(String::from(">")))
                }
            }
            ';' => {
                Token {
                    token_type: TokenType::Semicolon,
                    value: Some(Value::Str(String::from(";")))
                }
            }
            '(' => {
                Token {
                    token_type: TokenType::Lparen,
                    value: Some(Value::Str(String::from("(")))
                }
            }
            ')' => {
                Token {
                    token_type: TokenType::Rparen,
                    value: Some(Value::Str(String::from(")")))
                }
            }
            ',' => {
                Token {
                    token_type: TokenType::Comma,
                    value: Some(Value::Str(String::from(",")))
                }
            }
            '{' => {
                Token {
                    token_type: TokenType::LBRACE,
                    value: Some(Value::Str(String::from("{")))
                }
            }
            '}' => {
                Token {
                    token_type: TokenType::Rbrace,
                    value: Some(Value::Str(String::from("}")))
                }
            }
            '\0' => {
                Token {
                    token_type: TokenType::Eof,
                    value: Some(Value::Str(String::from("\0")))
                }
            }
            c => {
                if is_letter(c) {
                    let identifier = unsafe {self.read_identifier()};
                    Token {
                        token_type: unsafe {self.lookup_ident(&identifier)},
                        value: Some(Value::Str(identifier))
                    }
                } else if is_digit(c) {
                    Token {
                        token_type: TokenType::Int,
                        value: Some(Value::Str(unsafe { self.read_number()}))
                    }
                } else {
                    Token {
                        token_type: TokenType::Illegal,
                        value: None
                    }
                }
            }
        };
        self.read_char();
        token
    }

    pub unsafe fn read_identifier(&self) -> String {
        let start_position = self.position.get();
        while is_letter(self.ch.get()) {
            self.read_char();
        }
        let end_position = self.position.get();
        let s = self.input.slice_unchecked(start_position, end_position);
        s.to_string()
    }

    pub unsafe fn lookup_ident(&self, s: &str) -> TokenType {
        match s {
            "fn" => TokenType::Function,
            "let" => TokenType::Let,
            "true" => TokenType::True,
            "false" => TokenType::False,
            "if" => TokenType::If,
            "else" => TokenType::Else,
            "return" => TokenType::Return,
            _ => TokenType::Ident
        }
    }

    pub unsafe fn read_number(&self) -> String {
        let start_position = self.position.get();
        while is_digit(self.ch.get()) {
            self.read_char();
        }
        let end_position = self.position.get();
        let s = self.input.slice_unchecked(start_position, end_position);
        s.to_string()
    }

    pub fn skip_white_space(&self) {
        let ch = self.ch.get();
        while ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' {
            self.read_char();
        }
    }

    pub fn peek_char(&self) -> char {
        if self.read_position.get() >= self.input.len() {
            '0'
        } else {
            self.input.chars().nth(self.read_position.get()).unwrap()
        }
    }
}

fn is_letter(ch: char) -> bool {
    'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
}

fn is_digit(ch: char) -> bool {
    '0' <= ch && ch <= '9'
}

#[derive(Debug)]
pub enum Value {
    Str(String),
}

#[derive(Debug, PartialEq)]
pub enum TokenType {
    Illegal,
    Eof,

    Ident,
    Int,

    Assign,
    Plus,
    Minus,
    Bang,
    Asterisk,
    Slash,
    Eq,
    NotEq,

    Lt,
    Gt,

    Comma,
    Semicolon,

    Lparen,
    Rparen,
    LBRACE,
    Rbrace,

    Function,
    Let,
    True,
    False,
    If,
    Else,
    Return
}

#[derive(Debug)]
pub struct Token {
    pub token_type: TokenType,
    pub value: Option<Value>,
}

impl fmt::Display for Token  {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", 1.0)
    }
}

// Test
#[test]
fn peek_char() {
    let input = String::from("!=");
    let l = &Lexer::new(input);
    assert_eq!('=', l.peek_char());
    assert_eq!('=', l.peek_char());
}

#[test]
fn next_token_base() {
    let input = String::from("=()");
    let l = &Lexer::new(input);
    assert_eq!(l.next_token().token_type, TokenType::Assign);
    assert_eq!(l.next_token().token_type, TokenType::Lparen);
    assert_eq!(l.next_token().token_type, TokenType::Rparen);
}

#[test]
fn test_is_digit() {
    assert_eq!(is_digit('0'), true);
    assert_eq!(is_digit('1'), true);
    assert_eq!(is_digit('8'), true);
    assert_eq!(is_digit('9'), true);
}

#[test]
fn test_is_letter() {
    assert_eq!(is_letter('_'), true);
    assert_eq!(is_letter('a'), true);
    assert_eq!(is_letter('b'), true);
    assert_eq!(is_letter('y'), true);
    assert_eq!(is_letter('z'), true);
    assert_eq!(is_letter('A'), true);
    assert_eq!(is_letter('B'), true);
    assert_eq!(is_letter('Y'), true);
    assert_eq!(is_letter('Z'), true);
}

#[test]
fn next_token() {
    let input = String::from("let five = 5;
let ten = 10;

let add = fn(x, y) {
    x + y;
};

let result = add(five, ten);
!-/*5;
5 < 10 > 5;

if (5 < 10) {
    return true;
} else {
    return false;
}

10 == 10;
10 != 9;");
    let l = &Lexer::new(input);
    assert_eq!(l.next_token().token_type, TokenType::Let);
    assert_eq!(l.next_token().token_type, TokenType::Ident);
    assert_eq!(l.next_token().token_type, TokenType::Assign);
//    assert_eq!(l.next_token().token_type, TokenType::Int);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

pub mod tree;
pub mod parser;

use std::str::{self, FromStr};
use std::path::{PathBuf, Path};
use std::fs::File;
use std::io::Read;
use std::cmp::Ordering;
use std::borrow::Borrow;

use nom::{IResult, ErrorKind, Needed, FindSubstring, digit, space, multispace, line_ending};

use parser::escape_c_string;

named!(pub parse_include<String>, preceded!(
    tag!("/include/"),
    preceded!( multispace,
        delimited!(
            char!('"'),
            escape_c_string,
            char!('"')
        ))
));

named!(pub find_include<(&[u8], String)>, do_parse!(
    pre: take_until!("/include/") >>
    path: parse_include >>
    (pre, path)
));

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncludeBounds {
    pub path: PathBuf,
    pub global_start: usize,
    pub child_start: usize,
    pub len: usize,
    pub method: IncludeMethod,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IncludeMethod {
    DTS,
    CPP,
}

impl PartialOrd for IncludeBounds {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for IncludeBounds {
    fn cmp(&self, other: &Self) -> Ordering {
        use std::cmp::Ordering::*;
        match self.global_start.cmp(&other.global_start) {
            Equal => self.global_end().cmp(&other.global_end()),
            o => o,
        }
    }
}

impl IncludeBounds {
    pub fn global_end(&self) -> usize {
        self.global_start + self.len
    }

    pub fn split_bounds(bounds: &mut Vec<IncludeBounds>, start: usize, end: usize, offset: usize) {
        let mut remainders: Vec<IncludeBounds> = Vec::new();

        // println!("split s: {} e: {} off: {}", start, end, offset);

        for b in bounds.iter_mut() {
            // println!("g_start: {} g_end: {}", b.global_start, b.global_end());
            if b.global_start < start && b.global_end() >= start {
                // global_start -- start -- global_end
                let remainder = b.global_end() - start;

                // println!("remainder: {}", remainder);

                remainders.push(IncludeBounds {
                    path: b.path.clone(),
                    global_start: end,
                    child_start: b.child_start + start - b.global_start + offset,
                    len: remainder, // - offset,
                    method: b.method.clone(),
                });

                b.len = start - b.global_start;
            } else if b.global_start == start {
                // split is at begining of the bound
                // offset the start
                {
                    let offset = end - start;
                    b.global_start += offset;
                }
                // shrink the len by the offset
                b.len -= offset;
            }
        }

        bounds.extend_from_slice(&remainders);
        bounds.sort();
    }
}

#[derive(Debug, PartialEq)]
pub struct Linemarker {
    child_line: usize,
    path: PathBuf,
    flag: Option<LinemarkerFlag>,
}

#[derive(Debug, PartialEq)]
pub enum LinemarkerFlag {
    Start,
    Return,
    System,
    Extern,
}

named!(pub parse_linemarker<Linemarker>,
    complete!(do_parse!(
        tag!("#") >>
        opt!(tag!("line")) >>
        space >>
        line: map_res!(map_res!(digit, str::from_utf8), usize::from_str) >>
        space >>
        path: delimited!(
            char!('"'),
            map!(escape_c_string, PathBuf::from),
            char!('"')
        ) >>
        flag: opt!(preceded!(space, map_res!(map_res!(digit, str::from_utf8), u64::from_str))) >>
        line_ending >>
        (Linemarker {
            child_line: line,
            path: path,
            flag: flag.map(|f| match f {
                1 => LinemarkerFlag::Start,
                2 => LinemarkerFlag::Return,
                3 => LinemarkerFlag::System,
                4 => LinemarkerFlag::Extern,
                _ => unreachable!(),
            }),
        })
    ))
);

fn find_linemarker_start(input: &[u8]) -> IResult<&[u8], &[u8]> {
    if "# ".len() > input.len() {
        IResult::Incomplete(Needed::Size("# ".len()))
    } else {
        match input.find_substring("# ").iter().chain(input.find_substring("#line ").iter()).min() {
            None => {
                IResult::Error(error_position!(ErrorKind::TakeUntil, input))
            },
            Some(index) => {
                IResult::Done(&input[*index..], &input[0..*index])
            },
        }
    }
}

named!(find_linemarker<(&[u8], Linemarker)>, do_parse!(
    pre: find_linemarker_start >>
    marker: parse_linemarker >>
    (pre, marker)
));

fn parse_linemarkers(buf: &[u8], bounds: &mut Vec<IncludeBounds>, global_offset: usize) {
    let end_offset = global_offset + buf.len();
    // println!("{}", str::from_utf8(buf).unwrap());
    let mut buf = buf;
    println!("parsing linemarkers");
    loop {
        // look for linemarker
        if let IResult::Done(rem, (pre, marker)) = find_linemarker(buf) {
            // println!("{}", str::from_utf8(line).unwrap());
            // println!("{:?}", marker);
            // println!("pre.len() {}", pre.len());

            // double check that last bound was from a linemarker
            match bounds.last() {
                Some(&IncludeBounds { method: IncludeMethod::CPP, .. }) => {}
                _ => {
                    println!("{:#?}", bounds);
                    panic!("Linemarker found within DTS include")
                }
            }

            // end last
            bounds.last_mut().unwrap().len = pre.len();

            // start at new line
            let new_bound = IncludeBounds {
                path: marker.path.clone(),
                global_start: end_offset - rem.len(),
                child_start: File::open(&marker.path)
                                .map(|f| f.bytes().filter_map(|e| e.ok()))
                                .map(|b| line_to_byte_offset(b, marker.child_line).unwrap()) //TODO: unwraping is bad, SOK?
                                .unwrap_or(0),
                len: rem.len(),
                method: IncludeMethod::CPP,
            };

            bounds.push(new_bound);

            buf = rem;
        } else {
            return;
        }
    }
}

pub fn include_files(path: &Path,
                     main_offset: usize)
                     -> Result<(Vec<u8>, Vec<IncludeBounds>), String> {
    // TODO: check from parent directory of root file
    let mut file = File::open(path).unwrap();
    let mut buffer: Vec<u8> = Vec::new();
    let mut bounds: Vec<IncludeBounds> = Vec::new();

    let mut string_buffer = String::new();
    file.read_to_string(&mut string_buffer).map_err(|_| "IO Error".to_string())?;

    let mut buf = string_buffer.as_bytes();

    named!(first_linemarker<(&[u8], Linemarker)>,
        do_parse!(
            marker: peek!(parse_linemarker) >>
            line: recognize!(parse_linemarker) >>
            (line, marker)
        )
    );

    let start_bound = if let IResult::Done(rem, (line, marker)) = first_linemarker(buf) {
        let bound = IncludeBounds {
            path: marker.path.clone(),
            global_start: buf.len() - rem.len(),
            // TODO: check from parent directory of root file
            child_start: File::open(&marker.path)
                             .map(|f| f.bytes().filter_map(|e| e.ok()))
                             .map(|b| line_to_byte_offset(b, marker.child_line).unwrap()) //TODO: unwraping is bad, SOK?
                             .unwrap_or(0),
            len: File::open(&marker.path).unwrap().bytes().count(),
            method: IncludeMethod::CPP,
        };

        buffer.extend_from_slice(line);
        buf = rem;

        bound
    } else {
        // println!("main_offset {}", main_offset);
        IncludeBounds {
            path: path.to_path_buf(),
            global_start: main_offset,
            child_start: 0,
            // TODO: check from parent directory of root file
            len: File::open(path).unwrap().bytes().count(),
            method: IncludeMethod::DTS,
        }
    };
    bounds.push(start_bound);

    loop {
        // go until /include/
        if let IResult::Done(rem, (pre, file)) = find_include(&buf[..]) {
            parse_linemarkers(pre, &mut bounds, buffer.len());
            buffer.extend_from_slice(pre);

            let offset = pre.len();
            // println!("{}", file);
            // println!("Offset: {}", offset);
            // println!("{}", include_tree);

            let included_path = Path::new(&file);
            let total_len = buffer.len() + main_offset; // - 1;
            let (sub_buf, sub_bounds) = include_files(included_path, total_len)?;
            buffer.extend(sub_buf);

            let inc_start = sub_bounds.first()
                                      .map(|b| b.global_start)
                                      .expect(&format!("No bounds returned: {}",
                                                      included_path.to_string_lossy()));
            let inc_end = sub_bounds.last()
                                    .map(|b| b.global_end())
                                    .expect(&format!("No bounds returned: {}",
                                                    included_path.to_string_lossy()));
            let eaten_len = (buf.len() - offset) - rem.len();
            //include_tree.offset_after_location(inc_start,
            //                                   inc_end as isize - inc_start as isize -
            //                                   eaten_len as isize);
            // println!("After offset");
            // println!("{}", include_tree);
            IncludeBounds::split_bounds(&mut bounds, inc_start, inc_end, eaten_len);
            bounds.extend_from_slice(&sub_bounds);
            bounds.sort();

            // println!("After split");
            // println!("{}", include_tree);

            buf = rem;
        } else {
            parse_linemarkers(buf, &mut bounds, buffer.len());
            // no more includes, just add the rest and return
            buffer.extend(buf);
            return Ok((buffer, bounds));
        }
    }
}

pub fn line_to_byte_offset<K, I>(bytes: I, line: usize) -> Result<usize, String>
    where K: Borrow<u8> + Eq,
          I: Iterator<Item = K>
{
    if line == 1 {
        Ok(0)
    } else {
        bytes.enumerate()
            .filter(|&(_, ref byte)| byte.borrow() == &b'\n')
            .nth(line - 2)
            .map(|(offset, _)| offset + 1)
            .ok_or_else(|| "Failed converting from line to byte offset".to_string())
    }
}

pub fn byte_offset_to_line_col<K, I>(bytes: I, offset: usize) -> (usize, usize)
    where K: Borrow<u8> + Eq,
          I: Iterator<Item = K>
{
    let opt = bytes.enumerate()
        .filter(|&(off, ref byte)| off < offset && byte.borrow() == &b'\n')
        .map(|(start, _)| start)
        .enumerate()
        .last();

    match opt {
        Some((line, start)) => (line + 2, offset - start),
        None => (1, offset + 1),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nom::IResult;

    #[test]
    fn lines_to_bytes() {
        let string = "Howdy\nHow goes it\n\nI'm doing fine\n";
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 1).unwrap(),
                   0);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 2).unwrap(),
                   6);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 3).unwrap(),
                   18);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 4).unwrap(),
                   19);
    }

    #[test]
    fn bytes_to_lines() {
        let string = "Howdy\nHow goes it\n\nI'm doing fine\n";
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 0),
                   (1, 1));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 8),
                   (2, 3));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 20),
                   (4, 2));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 18),
                   (3, 1));
    }

    #[test]
    fn linemarker_no_flag() {
        let input = b"# 1 \"<built-in>\"\n";
        assert_eq!(
            parse_linemarker(input),
            IResult::Done(
                &b""[..],
                Linemarker {
                    child_line: 1,
                    path: PathBuf::from("<built-in>"),
                    flag: None,
                }
            )
        );
    }

    #[test]
    fn linemarker_flag() {
        let input = b"# 12 \"am33xx.dtsi\" 2\n";
        assert_eq!(
            parse_linemarker(input),
            IResult::Done(
                &b""[..],
                Linemarker {
                    child_line: 12,
                    path: PathBuf::from("am33xx.dtsi"),
                    flag: Some(LinemarkerFlag::Return),
                }
            )
        );
    }
}
<commit_msg>Replace `loop if let` with `while let` to improve code readability<commit_after>#[macro_use]
extern crate nom;

pub mod tree;
pub mod parser;

use std::str::{self, FromStr};
use std::path::{PathBuf, Path};
use std::fs::File;
use std::io::Read;
use std::cmp::Ordering;
use std::borrow::Borrow;

use nom::{IResult, ErrorKind, Needed, FindSubstring, digit, space, multispace, line_ending};

use parser::escape_c_string;

named!(pub parse_include<String>, preceded!(
    tag!("/include/"),
    preceded!( multispace,
        delimited!(
            char!('"'),
            escape_c_string,
            char!('"')
        ))
));

named!(pub find_include<(&[u8], String)>, do_parse!(
    pre: take_until!("/include/") >>
    path: parse_include >>
    (pre, path)
));

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncludeBounds {
    pub path: PathBuf,
    pub global_start: usize,
    pub child_start: usize,
    pub len: usize,
    pub method: IncludeMethod,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IncludeMethod {
    DTS,
    CPP,
}

impl PartialOrd for IncludeBounds {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for IncludeBounds {
    fn cmp(&self, other: &Self) -> Ordering {
        use std::cmp::Ordering::*;
        match self.global_start.cmp(&other.global_start) {
            Equal => self.global_end().cmp(&other.global_end()),
            o => o,
        }
    }
}

impl IncludeBounds {
    pub fn global_end(&self) -> usize {
        self.global_start + self.len
    }

    pub fn split_bounds(bounds: &mut Vec<IncludeBounds>, start: usize, end: usize, offset: usize) {
        let mut remainders: Vec<IncludeBounds> = Vec::new();

        // println!("split s: {} e: {} off: {}", start, end, offset);

        for b in bounds.iter_mut() {
            // println!("g_start: {} g_end: {}", b.global_start, b.global_end());
            if b.global_start < start && b.global_end() >= start {
                // global_start -- start -- global_end
                let remainder = b.global_end() - start;

                // println!("remainder: {}", remainder);

                remainders.push(IncludeBounds {
                    path: b.path.clone(),
                    global_start: end,
                    child_start: b.child_start + start - b.global_start + offset,
                    len: remainder, // - offset,
                    method: b.method.clone(),
                });

                b.len = start - b.global_start;
            } else if b.global_start == start {
                // split is at begining of the bound
                // offset the start
                {
                    let offset = end - start;
                    b.global_start += offset;
                }
                // shrink the len by the offset
                b.len -= offset;
            }
        }

        bounds.extend_from_slice(&remainders);
        bounds.sort();
    }
}

#[derive(Debug, PartialEq)]
pub struct Linemarker {
    child_line: usize,
    path: PathBuf,
    flag: Option<LinemarkerFlag>,
}

#[derive(Debug, PartialEq)]
pub enum LinemarkerFlag {
    Start,
    Return,
    System,
    Extern,
}

named!(pub parse_linemarker<Linemarker>,
    complete!(do_parse!(
        tag!("#") >>
        opt!(tag!("line")) >>
        space >>
        line: map_res!(map_res!(digit, str::from_utf8), usize::from_str) >>
        space >>
        path: delimited!(
            char!('"'),
            map!(escape_c_string, PathBuf::from),
            char!('"')
        ) >>
        flag: opt!(preceded!(space, map_res!(map_res!(digit, str::from_utf8), u64::from_str))) >>
        line_ending >>
        (Linemarker {
            child_line: line,
            path: path,
            flag: flag.map(|f| match f {
                1 => LinemarkerFlag::Start,
                2 => LinemarkerFlag::Return,
                3 => LinemarkerFlag::System,
                4 => LinemarkerFlag::Extern,
                _ => unreachable!(),
            }),
        })
    ))
);

fn find_linemarker_start(input: &[u8]) -> IResult<&[u8], &[u8]> {
    if "# ".len() > input.len() {
        IResult::Incomplete(Needed::Size("# ".len()))
    } else {
        match input.find_substring("# ").iter().chain(input.find_substring("#line ").iter()).min() {
            None => {
                IResult::Error(error_position!(ErrorKind::TakeUntil, input))
            },
            Some(index) => {
                IResult::Done(&input[*index..], &input[0..*index])
            },
        }
    }
}

named!(find_linemarker<(&[u8], Linemarker)>, do_parse!(
    pre: find_linemarker_start >>
    marker: parse_linemarker >>
    (pre, marker)
));

fn parse_linemarkers(buf: &[u8], bounds: &mut Vec<IncludeBounds>, global_offset: usize) {
    let end_offset = global_offset + buf.len();
    // println!("{}", str::from_utf8(buf).unwrap());
    let mut buf = buf;
    // println!("parsing linemarkers");
    while let IResult::Done(rem, (pre, marker)) = find_linemarker(buf) {
        // println!("{}", str::from_utf8(line).unwrap());
        // println!("{:?}", marker);
        // println!("pre.len() {}", pre.len());

        // double check that last bound was from a linemarker
        match bounds.last() {
            Some(&IncludeBounds { method: IncludeMethod::CPP, .. }) => {}
            _ => {
                println!("{:#?}", bounds);
                panic!("Linemarker found within DTS include")
            }
        }

        // end last
        bounds.last_mut().unwrap().len = pre.len();

        // start at new line
        let new_bound = IncludeBounds {
            path: marker.path.clone(),
            global_start: end_offset - rem.len(),
            child_start: File::open(&marker.path)
                            .map(|f| f.bytes().filter_map(|e| e.ok()))
                            .map(|b| line_to_byte_offset(b, marker.child_line).unwrap()) //TODO: unwraping is bad, SOK?
                            .unwrap_or(0),
            len: rem.len(),
            method: IncludeMethod::CPP,
        };

        bounds.push(new_bound);

        buf = rem;
    }
}

pub fn include_files(path: &Path,
                     main_offset: usize)
                     -> Result<(Vec<u8>, Vec<IncludeBounds>), String> {
    // TODO: check from parent directory of root file
    let mut file = File::open(path).unwrap();
    let mut buffer: Vec<u8> = Vec::new();
    let mut bounds: Vec<IncludeBounds> = Vec::new();

    let mut string_buffer = String::new();
    file.read_to_string(&mut string_buffer).map_err(|_| "IO Error".to_string())?;

    let mut buf = string_buffer.as_bytes();

    named!(first_linemarker<(&[u8], Linemarker)>,
        do_parse!(
            marker: peek!(parse_linemarker) >>
            line: recognize!(parse_linemarker) >>
            (line, marker)
        )
    );

    let start_bound = if let IResult::Done(rem, (line, marker)) = first_linemarker(buf) {
        let bound = IncludeBounds {
            path: marker.path.clone(),
            global_start: buf.len() - rem.len(),
            // TODO: check from parent directory of root file
            child_start: File::open(&marker.path)
                             .map(|f| f.bytes().filter_map(|e| e.ok()))
                             .map(|b| line_to_byte_offset(b, marker.child_line).unwrap()) //TODO: unwraping is bad, SOK?
                             .unwrap_or(0),
            len: File::open(&marker.path).unwrap().bytes().count(),
            method: IncludeMethod::CPP,
        };

        buffer.extend_from_slice(line);
        buf = rem;

        bound
    } else {
        // println!("main_offset {}", main_offset);
        IncludeBounds {
            path: path.to_path_buf(),
            global_start: main_offset,
            child_start: 0,
            // TODO: check from parent directory of root file
            len: File::open(path).unwrap().bytes().count(),
            method: IncludeMethod::DTS,
        }
    };
    bounds.push(start_bound);

    while let IResult::Done(rem, (pre, file)) = find_include(&buf[..]) {
        parse_linemarkers(pre, &mut bounds, buffer.len());
        buffer.extend_from_slice(pre);

        let offset = pre.len();
        // println!("{}", file);
        // println!("Offset: {}", offset);
        // println!("{}", include_tree);

        let included_path = Path::new(&file);
        let total_len = buffer.len() + main_offset; // - 1;
        let (sub_buf, sub_bounds) = include_files(included_path, total_len)?;
        buffer.extend(sub_buf);

        let inc_start = sub_bounds.first()
                                  .map(|b| b.global_start)
                                  .expect(&format!("No bounds returned: {}",
                                                  included_path.to_string_lossy()));
        let inc_end = sub_bounds.last()
                                .map(|b| b.global_end())
                                .expect(&format!("No bounds returned: {}",
                                                included_path.to_string_lossy()));
        let eaten_len = (buf.len() - offset) - rem.len();
        //include_tree.offset_after_location(inc_start,
        //                                   inc_end as isize - inc_start as isize -
        //                                   eaten_len as isize);
        // println!("After offset");
        // println!("{}", include_tree);
        IncludeBounds::split_bounds(&mut bounds, inc_start, inc_end, eaten_len);
        bounds.extend_from_slice(&sub_bounds);
        bounds.sort();

        // println!("After split");
        // println!("{}", include_tree);

        buf = rem;
    }

    // no more includes, just add the rest and return
    parse_linemarkers(buf, &mut bounds, buffer.len());
    buffer.extend(buf);

    Ok((buffer, bounds))
}

pub fn line_to_byte_offset<K, I>(bytes: I, line: usize) -> Result<usize, String>
    where K: Borrow<u8> + Eq,
          I: Iterator<Item = K>
{
    if line == 1 {
        Ok(0)
    } else {
        bytes.enumerate()
            .filter(|&(_, ref byte)| byte.borrow() == &b'\n')
            .nth(line - 2)
            .map(|(offset, _)| offset + 1)
            .ok_or_else(|| "Failed converting from line to byte offset".to_string())
    }
}

pub fn byte_offset_to_line_col<K, I>(bytes: I, offset: usize) -> (usize, usize)
    where K: Borrow<u8> + Eq,
          I: Iterator<Item = K>
{
    let opt = bytes.enumerate()
        .filter(|&(off, ref byte)| off < offset && byte.borrow() == &b'\n')
        .map(|(start, _)| start)
        .enumerate()
        .last();

    match opt {
        Some((line, start)) => (line + 2, offset - start),
        None => (1, offset + 1),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nom::IResult;

    #[test]
    fn lines_to_bytes() {
        let string = "Howdy\nHow goes it\n\nI'm doing fine\n";
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 1).unwrap(),
                   0);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 2).unwrap(),
                   6);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 3).unwrap(),
                   18);
        assert_eq!(line_to_byte_offset(string.as_bytes().iter(), 4).unwrap(),
                   19);
    }

    #[test]
    fn bytes_to_lines() {
        let string = "Howdy\nHow goes it\n\nI'm doing fine\n";
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 0),
                   (1, 1));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 8),
                   (2, 3));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 20),
                   (4, 2));
        assert_eq!(byte_offset_to_line_col(string.as_bytes().iter(), 18),
                   (3, 1));
    }

    #[test]
    fn linemarker_no_flag() {
        let input = b"# 1 \"<built-in>\"\n";
        assert_eq!(
            parse_linemarker(input),
            IResult::Done(
                &b""[..],
                Linemarker {
                    child_line: 1,
                    path: PathBuf::from("<built-in>"),
                    flag: None,
                }
            )
        );
    }

    #[test]
    fn linemarker_flag() {
        let input = b"# 12 \"am33xx.dtsi\" 2\n";
        assert_eq!(
            parse_linemarker(input),
            IResult::Done(
                &b""[..],
                Linemarker {
                    child_line: 12,
                    path: PathBuf::from("am33xx.dtsi"),
                    flag: Some(LinemarkerFlag::Return),
                }
            )
        );
    }
}
<|endoftext|>