<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
//

//! The filesystem abstraction code
//!
//! # Problem
//!
//! First, we had a compiletime backend for the store. This means that the actual filesystem
//! operations were compiled into the store either as real filesystem operations (in a normal debug
//! or release build) but as a in-memory variant in the 'test' case.
//! So tests did not hit the filesystem when running.
//! This gave us us the possibility to run tests concurrently with multiple
//! stores that did not interfere with eachother.
//!
//! This approach worked perfectly well until we started to test not the
//! store itself but crates that depend on the store implementation.
//! When running tests in a crate that depends on the store, the store
//! itself was compiled with the filesystem-hitting-backend.
//! This was problematic, as tests could not be implemented without hitting
//! the filesystem.
//!
//! Hence we implemented this.
//!
//! # Implementation
//!
//! The filesystem is abstracted via a trait `FileAbstraction` which
//! contains the essential functions for working with the filesystem.
//!
//! Two implementations are provided in the code:
//!
//! * FSFileAbstraction
//! * InMemoryFileAbstraction
//!
//! whereas the first actually works with the filesystem and the latter
//! works with an in-memory HashMap that is used as filesystem.
//!
//! Further, the trait `FileAbstractionInstance` was introduced for
//! functions which are executed on actual instances of content from the
//! filesystem, which was previousely tied into the general abstraction
//! mechanism.
//!
//! So, the `FileAbstraction` trait is for working with the filesystem, the
//! `FileAbstractionInstance` trait is for working with instances of content
//! from the filesystem (speak: actual Files).
//!
//! In case of the `FSFileAbstractionInstance`, which is the implementation
//! of the `FileAbstractionInstance` for the actual filesystem-hitting code,
//! the underlying resource is managed like with the old code before.
//! The `InMemoryFileAbstractionInstance` implementation is corrosponding to
//! the `InMemoryFileAbstraction` implementation - for the in-memory
//! "filesystem".
//!
//! The implementation of the `get_file_content()` function had to be
//! changed to return a `String` rather than a `&mut Read` because of
//! lifetime issues.
//! This change is store-internally and the API of the store itself was not
//! affected.
//!

use std::path::PathBuf;
use std::fmt::Debug;

use error::StoreError as SE;

pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance;

/// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug {
    fn remove_file(&self, path: &PathBuf) -> Result<(), SE>;
    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>;

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
}

/// An abstraction trait over actions on files
pub trait FileAbstractionInstance : Debug {
    fn get_file_content(&mut self) -> Result<String, SE>;
    fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE>;
}

mod fs {
    use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
    use std::io::{Seek, SeekFrom, Read};
    use std::path::{Path, PathBuf};

    use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

    use super::FileAbstraction;
    use super::FileAbstractionInstance;

    #[derive(Debug)]
    pub enum FSFileAbstractionInstance {
        Absent(PathBuf),
        File(File, PathBuf)
    }

    impl FileAbstractionInstance for FSFileAbstractionInstance {

        /**
         * Get the content behind this file
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotSeeked));

                    let mut s = String::new();
                    f.read_to_string(&mut s)
                        .map_err_into(SEK::IoError)
                        .map(|_| s)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
            } else {
                unreachable!()
            }
        }

        /**
         * Write the content of this file
         */
        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            use std::io::Write;
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotCreated));
                    f.write_all(buf).map_err_into(SEK::FileNotWritten)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                return f.write_all(buf).map_err_into(SEK::FileNotWritten);
            }
            unreachable!();
        }

    }

    /// `FSFileAbstraction` state type
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct FSFileAbstraction {
    }

    impl FSFileAbstraction {
        pub fn new() -> FSFileAbstraction {
            FSFileAbstraction { }
        }
    }

    impl FileAbstraction for FSFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            remove_file(path).map_err_into(SEK::FileNotRemoved)
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            rename(from, to).map_err_into(SEK::FileNotRenamed)
        }

        fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
            create_dir_all(path).map_err_into(SEK::DirNotCreated)
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(FSFileAbstractionInstance::Absent(p))
        }
    }

    fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        OpenOptions::new().write(true).read(true).open(p)
    }

    fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        if let Some(parent) = p.as_ref().parent() {
            debug!("Implicitely creating directory: {:?}", parent);
            if let Err(e) = create_dir_all(parent) {
                return Err(e);
            }
        }
        OpenOptions::new().write(true).read(true).create(true).open(p)
    }

}

mod inmemory {
    use error::StoreError as SE;
    use error::StoreErrorKind as SEK;
    use std::io::Read;
    use std::io::Cursor;
    use std::path::PathBuf;
    use std::collections::HashMap;
    use std::sync::Mutex;
    use std::cell::RefCell;
    use std::sync::Arc;

    use libimagerror::into::IntoError;

    use super::FileAbstraction;
    use super::FileAbstractionInstance;
    use error::MapErrInto;

    type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Cursor<Vec<u8>>>>>>;

    /// `FileAbstraction` type, this is the Test version!
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct InMemoryFileAbstractionInstance {
        fs_abstraction: Backend,
        absent_path: PathBuf,
    }

    impl InMemoryFileAbstractionInstance {

        pub fn new(fs: Backend, pb: PathBuf) -> InMemoryFileAbstractionInstance {
            InMemoryFileAbstractionInstance {
                fs_abstraction: fs,
                absent_path: pb
            }
        }

    }

    impl FileAbstractionInstance for InMemoryFileAbstractionInstance {

        /**
         * Get the mutable file behind a InMemoryFileAbstraction object
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);

            let p = self.absent_path.clone();
            match self.fs_abstraction.lock() {
                Ok(mut mtx) => {
                    mtx.get_mut()
                        .get_mut(&p)
                        .ok_or(SEK::FileNotFound.into_error())
                        .and_then(|t| {
                            let mut s = String::new();
                            t.read_to_string(&mut s)
                                .map_err_into(SEK::IoError)
                                .map(|_| s)
                        })
                }

                Err(_) => Err(SEK::LockError.into_error())
            }
        }

        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            match *self {
                InMemoryFileAbstractionInstance { ref absent_path, .. } => {
                    let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
                    let mut backend = mtx.get_mut();

                    if let Some(ref mut cur) = backend.get_mut(absent_path) {
                        let mut vec = cur.get_mut();
                        vec.clear();
                        vec.extend_from_slice(buf);
                        return Ok(());
                    }
                    let vec = Vec::from(buf);
                    backend.insert(absent_path.clone(), Cursor::new(vec));
                    return Ok(());
                },
            };
        }
    }

    #[derive(Debug)]
    pub struct InMemoryFileAbstraction {
        virtual_filesystem: Backend,
    }

    impl InMemoryFileAbstraction {

        pub fn new() -> InMemoryFileAbstraction {
            InMemoryFileAbstraction {
                virtual_filesystem: Arc::new(Mutex::new(RefCell::new(HashMap::new()))),
            }
        }

        pub fn backend(&self) -> &Backend {
            &self.virtual_filesystem
        }

    }

    impl FileAbstraction for InMemoryFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            debug!("Removing: {:?}", path);
            self.backend()
                .lock()
                .expect("Locking Mutex failed")
                .get_mut()
                .remove(path)
                .map(|_| ())
                .ok_or(SEK::FileNotFound.into_error())
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Copying : {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Copying: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Renaming: {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Renaming: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> {
            Ok(())
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
        }
    }

}

#[cfg(test)]
mod test {
    use super::FileAbstractionInstance;
    use super::inmemory::InMemoryFileAbstraction;
    use super::inmemory::InMemoryFileAbstractionInstance;
    use std::path::PathBuf;

    #[test]
    fn lazy_file() {
        let fs = InMemoryFileAbstraction::new();

        let mut path = PathBuf::from("/tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path);
        lf.write_file_content(b"Hello World").unwrap();
        let bah = lf.get_file_content().unwrap();
        assert_eq!(bah, "Hello World");
    }

}
<commit_msg>Implement backend code for in-memory IO backend<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
//

//! The filesystem abstraction code
//!
//! # Problem
//!
//! First, we had a compiletime backend for the store. This means that the actual filesystem
//! operations were compiled into the store either as real filesystem operations (in a normal debug
//! or release build) but as a in-memory variant in the 'test' case.
//! So tests did not hit the filesystem when running.
//! This gave us us the possibility to run tests concurrently with multiple
//! stores that did not interfere with eachother.
//!
//! This approach worked perfectly well until we started to test not the
//! store itself but crates that depend on the store implementation.
//! When running tests in a crate that depends on the store, the store
//! itself was compiled with the filesystem-hitting-backend.
//! This was problematic, as tests could not be implemented without hitting
//! the filesystem.
//!
//! Hence we implemented this.
//!
//! # Implementation
//!
//! The filesystem is abstracted via a trait `FileAbstraction` which
//! contains the essential functions for working with the filesystem.
//!
//! Two implementations are provided in the code:
//!
//! * FSFileAbstraction
//! * InMemoryFileAbstraction
//!
//! whereas the first actually works with the filesystem and the latter
//! works with an in-memory HashMap that is used as filesystem.
//!
//! Further, the trait `FileAbstractionInstance` was introduced for
//! functions which are executed on actual instances of content from the
//! filesystem, which was previousely tied into the general abstraction
//! mechanism.
//!
//! So, the `FileAbstraction` trait is for working with the filesystem, the
//! `FileAbstractionInstance` trait is for working with instances of content
//! from the filesystem (speak: actual Files).
//!
//! In case of the `FSFileAbstractionInstance`, which is the implementation
//! of the `FileAbstractionInstance` for the actual filesystem-hitting code,
//! the underlying resource is managed like with the old code before.
//! The `InMemoryFileAbstractionInstance` implementation is corrosponding to
//! the `InMemoryFileAbstraction` implementation - for the in-memory
//! "filesystem".
//!
//! The implementation of the `get_file_content()` function had to be
//! changed to return a `String` rather than a `&mut Read` because of
//! lifetime issues.
//! This change is store-internally and the API of the store itself was not
//! affected.
//!

use std::path::PathBuf;
use std::fmt::Debug;

use error::StoreError as SE;

pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance;

/// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug {
    fn remove_file(&self, path: &PathBuf) -> Result<(), SE>;
    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE>;
    fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE>;

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance>;
}

/// An abstraction trait over actions on files
pub trait FileAbstractionInstance : Debug {
    fn get_file_content(&mut self) -> Result<String, SE>;
    fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE>;
}

mod fs {
    use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
    use std::io::{Seek, SeekFrom, Read};
    use std::path::{Path, PathBuf};

    use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

    use super::FileAbstraction;
    use super::FileAbstractionInstance;

    #[derive(Debug)]
    pub enum FSFileAbstractionInstance {
        Absent(PathBuf),
        File(File, PathBuf)
    }

    impl FileAbstractionInstance for FSFileAbstractionInstance {

        /**
         * Get the content behind this file
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotSeeked));

                    let mut s = String::new();
                    f.read_to_string(&mut s)
                        .map_err_into(SEK::IoError)
                        .map(|_| s)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
            } else {
                unreachable!()
            }
        }

        /**
         * Write the content of this file
         */
        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            use std::io::Write;
            let (file, path) = match *self {
                FSFileAbstractionInstance::File(ref mut f, _) => return {
                    // We seek to the beginning of the file since we expect each
                    // access to the file to be in a different context
                    try!(f.seek(SeekFrom::Start(0))
                        .map_err_into(SEK::FileNotCreated));
                    f.write_all(buf).map_err_into(SEK::FileNotWritten)
                },
                FSFileAbstractionInstance::Absent(ref p) =>
                    (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
            };
            *self = FSFileAbstractionInstance::File(file, path);
            if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
                return f.write_all(buf).map_err_into(SEK::FileNotWritten);
            }
            unreachable!();
        }

    }

    /// `FSFileAbstraction` state type
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct FSFileAbstraction {
    }

    impl FSFileAbstraction {
        pub fn new() -> FSFileAbstraction {
            FSFileAbstraction { }
        }
    }

    impl FileAbstraction for FSFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            remove_file(path).map_err_into(SEK::FileNotRemoved)
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            rename(from, to).map_err_into(SEK::FileNotRenamed)
        }

        fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
            create_dir_all(path).map_err_into(SEK::DirNotCreated)
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(FSFileAbstractionInstance::Absent(p))
        }
    }

    fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        OpenOptions::new().write(true).read(true).open(p)
    }

    fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
        if let Some(parent) = p.as_ref().parent() {
            debug!("Implicitely creating directory: {:?}", parent);
            if let Err(e) = create_dir_all(parent) {
                return Err(e);
            }
        }
        OpenOptions::new().write(true).read(true).create(true).open(p)
    }

}

mod inmemory {
    use error::StoreError as SE;
    use error::StoreErrorKind as SEK;
    use std::io::Read;
    use std::io::Cursor;
    use std::path::PathBuf;
    use std::collections::HashMap;
    use std::sync::Mutex;
    use std::cell::RefCell;
    use std::sync::Arc;

    use libimagerror::into::IntoError;

    use super::FileAbstraction;
    use super::FileAbstractionInstance;
    use error::MapErrInto;

    type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Cursor<Vec<u8>>>>>>;

    /// `FileAbstraction` type, this is the Test version!
    ///
    /// A lazy file is either absent, but a path to it is available, or it is present.
    #[derive(Debug)]
    pub struct InMemoryFileAbstractionInstance {
        fs_abstraction: Backend,
        absent_path: PathBuf,
    }

    impl InMemoryFileAbstractionInstance {

        pub fn new(fs: Backend, pb: PathBuf) -> InMemoryFileAbstractionInstance {
            InMemoryFileAbstractionInstance {
                fs_abstraction: fs,
                absent_path: pb
            }
        }

    }

    impl FileAbstractionInstance for InMemoryFileAbstractionInstance {

        /**
         * Get the mutable file behind a InMemoryFileAbstraction object
         */
        fn get_file_content(&mut self) -> Result<String, SE> {
            debug!("Getting lazy file: {:?}", self);

            let p = self.absent_path.clone();
            match self.fs_abstraction.lock() {
                Ok(mut mtx) => {
                    mtx.get_mut()
                        .get_mut(&p)
                        .ok_or(SEK::FileNotFound.into_error())
                        .and_then(|t| {
                            let mut s = String::new();
                            t.read_to_string(&mut s)
                                .map_err_into(SEK::IoError)
                                .map(|_| s)
                        })
                }

                Err(_) => Err(SEK::LockError.into_error())
            }
        }

        fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> {
            match *self {
                InMemoryFileAbstractionInstance { ref absent_path, .. } => {
                    let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
                    let mut backend = mtx.get_mut();

                    if let Some(ref mut cur) = backend.get_mut(absent_path) {
                        let mut vec = cur.get_mut();
                        vec.clear();
                        vec.extend_from_slice(buf);
                        return Ok(());
                    }
                    let vec = Vec::from(buf);
                    backend.insert(absent_path.clone(), Cursor::new(vec));
                    return Ok(());
                },
            };
        }
    }

    #[derive(Debug)]
    pub struct InMemoryFileAbstraction {
        virtual_filesystem: Backend,
    }

    impl InMemoryFileAbstraction {

        pub fn new() -> InMemoryFileAbstraction {
            InMemoryFileAbstraction {
                virtual_filesystem: Arc::new(Mutex::new(RefCell::new(HashMap::new()))),
            }
        }

        pub fn backend(&self) -> &Backend {
            &self.virtual_filesystem
        }

    }

    impl FileAbstraction for InMemoryFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            debug!("Removing: {:?}", path);
            self.backend()
                .lock()
                .expect("Locking Mutex failed")
                .get_mut()
                .remove(path)
                .map(|_| ())
                .ok_or(SEK::FileNotFound.into_error())
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Copying : {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Copying: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            debug!("Renaming: {:?} -> {:?}", from, to);
            let mut mtx = self.backend().lock().expect("Locking Mutex failed");
            let mut backend = mtx.get_mut();

            let a = try!(backend.get(from).cloned().ok_or(SEK::FileNotFound.into_error()));
            backend.insert(to.clone(), a);
            debug!("Renaming: {:?} -> {:?} worked", from, to);
            Ok(())
        }

        fn create_dir_all(&self, _: &PathBuf) -> Result<(), SE> {
            Ok(())
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
        }
    }

}

mod stdio {
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::fmt::Debug;
    use std::fmt::Error as FmtError;
    use std::fmt::Formatter;
    use std::io::Cursor;
    use std::io::{Read, Write};
    use std::path::PathBuf;
    use std::sync::Arc;
    use std::sync::Mutex;

    use error::StoreError as SE;
    use super::FileAbstraction;
    use super::FileAbstractionInstance;
    use super::InMemoryFileAbstraction;

    // Because this is not exported in super::inmemory;
    type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Cursor<Vec<u8>>>>>>;

    pub struct StdIoFileAbstraction {
        mem: InMemoryFileAbstraction,
        stdin: Box<Read>,
        stdout: Box<Write>,
    }

    impl Debug for StdIoFileAbstraction {
        fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
            write!(f, "StdIoFileAbstraction({:?}", self.mem)
        }
    }

    impl StdIoFileAbstraction {

        pub fn new(in_stream: Box<Read>, out_stream: Box<Write>) -> StdIoFileAbstraction {
            StdIoFileAbstraction {
                mem: InMemoryFileAbstraction::new(),
                stdin: in_stream,
                stdout: out_stream
            }
        }

        pub fn backend(&self) -> &Backend {
            &self.mem.backend()
        }

    }

    impl FileAbstraction for StdIoFileAbstraction {

        fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
            self.mem.remove_file(path)
        }

        fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            self.mem.copy(from, to)
        }

        fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
            self.mem.rename(from, to)
        }

        fn create_dir_all(&self, pb: &PathBuf) -> Result<(), SE> {
            self.mem.create_dir_all(pb)
        }

        fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
            self.mem.new_instance(p)
        }
    }

}

#[cfg(test)]
mod test {
    use super::FileAbstractionInstance;
    use super::inmemory::InMemoryFileAbstraction;
    use super::inmemory::InMemoryFileAbstractionInstance;
    use std::path::PathBuf;

    #[test]
    fn lazy_file() {
        let fs = InMemoryFileAbstraction::new();

        let mut path = PathBuf::from("/tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path);
        lf.write_file_content(b"Hello World").unwrap();
        let bah = lf.get_file_content().unwrap();
        assert_eq!(bah, "Hello World");
    }

}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::{CStr, CString};
use std::fmt;

use ::LLVMErr;

use ::types::*;
use ::value::*;

#[link(name = "LLVM-4.0")]
extern "C" {
    fn LLVMModuleCreateWithName(s: *const libc::c_char) -> *const CModule;
    fn LLVMPrintModuleToString(m: *const CModule) -> *const libc::c_char;
    fn LLVMDisposeModule(m: *const CModule);

    fn LLVMAddFunction(m: *const CModule, nm: *const libc::c_char, tp: *const CType) -> *const CValue;
    fn LLVMGetNamedFunction(m: *const CModule, nm: *const libc::c_char) -> *const CValue;
}

pub(super) enum CModule {}

pub struct Module {
    pub name: String,
    pub(super) inner: *const CModule
}

impl Module {
    pub fn new_with_name(name: &str) -> Self {
        let c_name = CString::new(name).unwrap();

        let c_modl = unsafe { LLVMModuleCreateWithName(c_name.as_ptr()) };
        Module{name: name.to_string(), inner: c_modl}
    }

    pub fn add_function(&self, name: &str, tp: Type) -> Value {
        debug_assert!(tp.kind() == TypeKind::Function);

        let c_name = CString::new(name).unwrap();
        Value{inner: unsafe { LLVMAddFunction(self.inner, c_name.as_ptr(), tp.inner) } }
    }

    pub fn find_function(&self, name: &str) -> Option<Value> {
        let c_name = CString::new(name).unwrap();

        let f = unsafe { LLVMGetNamedFunction(self.inner, c_name.as_ptr()) };

        if f.is_null() { None } else { Some(Value{inner: f }) }
    }
}

impl fmt::Debug for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let c_s = unsafe { CStr::from_ptr(LLVMPrintModuleToString(self.inner)) };
        let st = c_s.to_str().unwrap(); // Propably valid utf8
        write!(f, "{}", st)
    }
}

impl Drop for Module {
    fn drop(&mut self) {
        unsafe { LLVMDisposeModule(self.inner) }
    }
}

#[test]
fn test_add_function() {
    let modl = Module::new_with_name("test");
    let f = modl.add_function("testf", Type::function_type(Type::int32(), &vec![], false));
    assert!(modl.find_function("testf").is_some());
}
<commit_msg>Module functions vector (LLVMGetFirstFunction & LLVMGetNextFunction)<commit_after>extern crate libc;

use std::ffi::{CStr, CString};
use std::fmt;

use ::types::*;
use ::value::*;

#[link(name = "LLVM-4.0")]
extern "C" {
    fn LLVMModuleCreateWithName(s: *const libc::c_char) -> *const CModule;
    fn LLVMPrintModuleToString(m: *const CModule) -> *const libc::c_char;
    fn LLVMDisposeModule(m: *const CModule);

    fn LLVMAddFunction(m: *const CModule, nm: *const libc::c_char, tp: *const CType) -> *const CValue;
    fn LLVMGetNamedFunction(m: *const CModule, nm: *const libc::c_char) -> *const CValue;
    fn LLVMGetFirstFunction(m: *const CModule) -> *const CValue;
    fn LLVMGetNextFunction(m: *const CValue) -> *const CValue;
}

pub(super) enum CModule {}

pub struct Module {
    pub name: String,
    pub(super) inner: *const CModule,
}

impl Module {
    pub fn new_with_name(name: &str) -> Self {
        let c_name = CString::new(name).unwrap();

        let c_modl = unsafe { LLVMModuleCreateWithName(c_name.as_ptr()) };
        Module{name: name.to_string(), inner: c_modl}
    }

    pub fn add_function(&self, name: &str, tp: Type) -> Value {
        debug_assert!(tp.kind() == TypeKind::Function);

        let c_name = CString::new(name).unwrap();
        Value{inner: unsafe { LLVMAddFunction(self.inner, c_name.as_ptr(), tp.inner) } }
    }

    pub fn find_function(&self, name: &str) -> Option<Value> {
        let c_name = CString::new(name).unwrap();

        let f = unsafe { LLVMGetNamedFunction(self.inner, c_name.as_ptr()) };

        if f.is_null() { None } else { Some(Value{inner: f }) }
    }

    pub fn functions(&self) -> Vec<Value> {
        let f = unsafe { LLVMGetFirstFunction(self.inner) };
        if f.is_null() {
            vec![]
        } else {
            let mut res = vec![Value{inner: f}];
            let mut current = f;
            loop {
                let next = unsafe { LLVMGetNextFunction(current) };
                if !next.is_null() {
                    res.push(Value{inner: next});
                    current = next;
                } else {
                    break;
                }
            }
            res
        }
    }
}

impl fmt::Debug for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let c_s = unsafe { CStr::from_ptr(LLVMPrintModuleToString(self.inner)) };
        let st = c_s.to_str().unwrap(); // Propably valid utf8
        write!(f, "{}", st)
    }
}

impl Drop for Module {
    fn drop(&mut self) {
        unsafe { LLVMDisposeModule(self.inner) }
    }
}

#[test]
fn test_add_function() {
    let modl = Module::new_with_name("test");
    let _ = modl.add_function("testf", Type::function_type(Type::int32(), &vec![], false));
    assert!(modl.find_function("testf").is_some());
    let _ = modl.add_function("testf2", Type::function_type(Type::int32(), &vec![], false));

    assert!(modl.functions().len() == 2);
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::result;

#[derive(Debug)]
pub struct JobRequireVariablePair {
    pub id: i32,
    pub fk_job: i32,
    pub fk_variable_pair: i32,
}

pub fn table_create_job_require_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE JOB_REQUIRE_VALUE (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_job           INTEGER NOT NULL,
                  fk_variable_pair INTEGER NOT NULL,
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable_pair) REFERENCES VARIABLE_PAIR(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        println!(
            "table_create_job_require_variable_pair Failed {:?}",
            load_table
        );
        return;
    }
    load_table.unwrap();
}

pub fn insert_job_require_variable_pair(
    conn: &Connection,
    job: &i32,
    variable_pair: &i32,
) -> Result<i32, &'static str> {
    let me = JobRequireVariablePair {
        id: 0,
        fk_job: *job,
        fk_variable_pair: *variable_pair,
    };
    let variable_pair_instance = conn.execute(
        "INSERT INTO JOB_REQUIRE_VALUE (fk_job, fk_variable_pair)
                  VALUES (?1, ?2)",
        &[&me.fk_job, &me.fk_variable_pair],
    );
    if variable_pair_instance.is_err() {
        return Err("Insert failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_job_require_variable_pair(conn: &Connection) -> Vec<JobRequireVariablePair> {
    let mut stmt = conn.prepare(
        "SELECT id, fk_job, fk_variable_pair  FROM JOB_REQUIRE_VALUE",
    ).unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    let mut items = Vec::<JobRequireVariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn job_require_variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable_pair FROM JOB_REQUIRE_VALUE")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_job_require_variable_pair_by_all(
    conn: &Connection,
    job: &i32,
    variable_pair: &i32,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let mut stmt = conn.prepare("SELECT JOB_REQUIRE_VALUE.id, JOB_REQUIRE_VALUE.fk_job, JOB_REQUIRE_VALUE.fk_variable_pair  FROM JOB_REQUIRE_VALUE WHERE JOB_REQUIRE_VALUE.fk_job = ?1 AND JOB_REQUIRE_VALUE.fk_variable_pair = ?2").unwrap();
    let variable_pair_iter = stmt.query_map(&[job, variable_pair], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<commit_msg>Use Logging<commit_after>use rusqlite::Connection;
use std::result;
use log;

#[derive(Debug)]
pub struct JobRequireVariablePair {
    pub id: i32,
    pub fk_job: i32,
    pub fk_variable_pair: i32,
}

pub fn table_create_job_require_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE JOB_REQUIRE_VALUE (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_job           INTEGER NOT NULL,
                  fk_variable_pair INTEGER NOT NULL,
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable_pair) REFERENCES VARIABLE_PAIR(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        error!(
            "table_create_job_require_variable_pair Failed {:?}",
            load_table
        );
        return;
    }
    load_table.unwrap();
}

pub fn insert_job_require_variable_pair(
    conn: &Connection,
    job: &i32,
    variable_pair: &i32,
) -> Result<i32, &'static str> {
    let me = JobRequireVariablePair {
        id: 0,
        fk_job: *job,
        fk_variable_pair: *variable_pair,
    };
    let variable_pair_instance = conn.execute(
        "INSERT INTO JOB_REQUIRE_VALUE (fk_job, fk_variable_pair)
                  VALUES (?1, ?2)",
        &[&me.fk_job, &me.fk_variable_pair],
    );
    if variable_pair_instance.is_err() {
        return Err("Insert failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_job_require_variable_pair(conn: &Connection) -> Vec<JobRequireVariablePair> {
    let mut stmt = conn.prepare(
        "SELECT id, fk_job, fk_variable_pair  FROM JOB_REQUIRE_VALUE",
    ).unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    let mut items = Vec::<JobRequireVariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn job_require_variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable_pair FROM JOB_REQUIRE_VALUE")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        info!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_job_require_variable_pair_by_all(
    conn: &Connection,
    job: &i32,
    variable_pair: &i32,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let mut stmt = conn.prepare("SELECT JOB_REQUIRE_VALUE.id, JOB_REQUIRE_VALUE.fk_job, JOB_REQUIRE_VALUE.fk_variable_pair  FROM JOB_REQUIRE_VALUE WHERE JOB_REQUIRE_VALUE.fk_job = ?1 AND JOB_REQUIRE_VALUE.fk_variable_pair = ?2").unwrap();
    let variable_pair_iter = stmt.query_map(&[job, variable_pair], |row| {
        JobRequireVariablePair {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable_pair: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    let mut items = Vec::<i32>::new();
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::{ Display, Error, Formatter };

#[derive(Debug, PartialEq)]
pub enum JsonOption {
    Object(HashMap<String, JsonOption>),
    Array(Vec<JsonOption>),
    String(String),
    Integer(i32),
    Number(f32),
    None,
}

impl JsonOption {
    pub fn object(&self) -> &Self {
        match *self {
            JsonOption::Object(_) => self,
            _ => panic!("Expecting Object got {}", self),
        }
    }

    pub fn array(&self) -> &Self {
        match *self {
            JsonOption::Array(_) => self,
            _ => panic!("Expecting Array got {}", self),
        }
    }

    pub fn string(&self) -> &Self {
        match *self {
            JsonOption::String(_) => self,
            _ => panic!("Expecting String got {}", self),
        }
    }

    pub fn integer(&self) -> &Self {
        match *self {
            JsonOption::Integer(_) => self,
            _ => panic!("Expecting Integer got {}", self),
        }
    }

    pub fn number(&self) -> &Self {
        match *self {
            JsonOption::Number(_) => self,
            _ => panic!("Expecting Number got {}", self),
        }
    }

    pub fn none(&self) -> &Self {
        match *self {
            JsonOption::None => self,
            _ => panic!("Expecting None got {}", self),
        }
    }
}

impl Display for JsonOption {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        match *self {
            JsonOption::Object(ref object) => {
                write!(formatter, "{:?}", object)
            },
            JsonOption::Array(ref vector) => {
                write!(formatter, "{:?}", vector)
            },
            JsonOption::String(ref string) => {
                write!(formatter, "String({})", string)
            },
            JsonOption::Integer(integer) => {
                write!(formatter, "Integer({})", integer)
            },
            JsonOption::Number(number) => {
                write!(formatter, "Number({})", number)
            },
            JsonOption::None => {
                write!(formatter, "None")
            },
        }
    }
}

<commit_msg>Some improvements on the auxiliary functions<commit_after>use std::collections::HashMap;
use std::fmt::{ Display, Error, Formatter };

#[derive(Debug, PartialEq)]
pub enum JsonOption {
    Object(HashMap<String, JsonOption>),
    Array(Vec<JsonOption>),
    String(String),
    Integer(i32),
    Number(f32),
    None,
}

impl JsonOption {
    pub fn object(&self) -> &HashMap<String, JsonOption> {
        match *self {
            JsonOption::Object(ref object) => object,
            _ => panic!("Expecting Object got {}", self),
        }
    }

    pub fn array(&self) -> &Vec<JsonOption> {
        match *self {
            JsonOption::Array(ref array) => array,
            _ => panic!("Expecting Array got {}", self),
        }
    }

    pub fn string(&self) -> &String {
        match *self {
            JsonOption::String(ref string) => string,
            _ => panic!("Expecting String got {}", self),
        }
    }

    pub fn integer(&self) -> &i32 {
        match *self {
            JsonOption::Integer(ref integer) => integer,
            _ => panic!("Expecting Integer got {}", self),
        }
    }

    pub fn number(&self) -> &f32 {
        match *self {
            JsonOption::Number(ref number) => number,
            _ => panic!("Expecting Number got {}", self),
        }
    }

    pub fn none(&self) {
        match *self {
            _ => panic!("Expecting None got {}", self),
        }
    }
}

impl Display for JsonOption {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        match *self {
            JsonOption::Object(ref object) => {
                write!(formatter, "{:?}", object)
            },
            JsonOption::Array(ref vector) => {
                write!(formatter, "{:?}", vector)
            },
            JsonOption::String(ref string) => {
                write!(formatter, "String({})", string)
            },
            JsonOption::Integer(integer) => {
                write!(formatter, "Integer({})", integer)
            },
            JsonOption::Number(number) => {
                write!(formatter, "Number({})", number)
            },
            JsonOption::None => {
                write!(formatter, "None")
            },
        }
    }
}

<|endoftext|>


<commit_before>use internal::{FdOptions, PathDisplay, ROOT_DIR};
use lscolors::LsColors;

use std::{fs, process};
use std::io::{self, Write};
use std::ops::Deref;
use std::path::{self, Path, PathBuf, Component};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use ansi_term;

pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(base, entry, config, ls_colors)
    } else {
        print_entry_uncolorized(entry, config)
    };

    if r.is_err() {
        // Probably a broken pipe. Exit gracefully.
        process::exit(0);
    }
}

fn print_entry_colorized(
    base: &Path,
    entry: &PathBuf,
    config: &FdOptions,
    ls_colors: &LsColors,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    let mut component_path = base.to_path_buf();

    let stdout = io::stdout();
    let mut handle = stdout.lock();

    let path_full = base.join(entry);

    if config.path_display == PathDisplay::Absolute {
        write!(handle, "{}", ls_colors.directory.paint(ROOT_DIR))?;
    }

    // Traverse the path and colorize each component
    for component in entry.components() {
        let comp_str = component.as_os_str().to_string_lossy();

        component_path.push(Path::new(comp_str.deref()));

        if let Component::RootDir = component {
            // Printing the root dir would result in too many path separators on Windows.
            // Note that a root dir component won't occur on Unix, because `entry` is never an
            // absolute path in that case.
            continue;
        }

        let metadata = component_path.metadata();
        let is_directory = metadata.as_ref().map(|md| md.is_dir()).unwrap_or(false);

        let style = if component_path
            .symlink_metadata()
            .map(|md| md.file_type().is_symlink())
            .unwrap_or(false)
        {
            &ls_colors.symlink
        } else if is_directory {
            &ls_colors.directory
        } else if metadata.map(|md| is_executable(&md)).unwrap_or(false) {
            &ls_colors.executable
        } else {
            // Look up file name
            let o_style = component_path
                .file_name()
                .and_then(|n| n.to_str())
                .and_then(|n| ls_colors.filenames.get(n));

            match o_style {
                        Some(s) => s,
                        None =>
                            // Look up file extension
                            component_path.extension()
                                          .and_then(|e| e.to_str())
                                          .and_then(|e| ls_colors.extensions.get(e))
                                          .unwrap_or(&default_style)
                    }
        };

        write!(handle, "{}", style.paint(comp_str))?;

        if is_directory && component_path != path_full {
            let sep = path::MAIN_SEPARATOR.to_string();
            write!(handle, "{}", style.paint(sep))?;
        }
    }

    if config.null_separator {
        write!(handle, "\0")
    } else {
        writeln!(handle, "")
    }
}

fn print_entry_uncolorized(entry: &PathBuf, config: &FdOptions) -> io::Result<()> {
    // Uncolorized output
    let prefix = if config.path_display == PathDisplay::Absolute {
        ROOT_DIR
    } else {
        ""
    };
    let separator = if config.null_separator { "\0" } else { "\n" };

    let path_str = entry.to_string_lossy();
    write!(&mut io::stdout(), "{}{}{}", prefix, path_str, separator)
}

#[cfg(unix)]
fn is_executable(md: &fs::Metadata) -> bool {
    md.permissions().mode() & 0o111 != 0
}

#[cfg(windows)]
fn is_executable(_: &fs::Metadata) -> bool {
    false
}
<commit_msg>Refactor output.rs<commit_after>use internal::{FdOptions, PathDisplay};
use lscolors::LsColors;

use std::{fs, process};
use std::io::{self, Write};
use std::ops::Deref;
use std::path::{self, Path, PathBuf, Component};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use ansi_term;

pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
    let path_full = base.join(entry);

    let path_to_print = if config.path_display == PathDisplay::Absolute {
        &path_full
    } else {
        entry
    };

    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(base, path_to_print, config, ls_colors)
    } else {
        print_entry_uncolorized(path_to_print, config)
    };

    if r.is_err() {
        // Probably a broken pipe. Exit gracefully.
        process::exit(0);
    }
}

fn print_entry_colorized(
    base: &Path,
    path: &Path,
    config: &FdOptions,
    ls_colors: &LsColors,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    let stdout = io::stdout();
    let mut handle = stdout.lock();

    // Separator to use before the current component.
    let mut separator = String::new();

    // Full path to the current component.
    let mut component_path = base.to_path_buf();

    // Traverse the path and colorize each component
    for component in path.components() {
        let comp_str = component.as_os_str().to_string_lossy();
        component_path.push(Path::new(comp_str.deref()));

        let style = get_path_style(&component_path, ls_colors).unwrap_or(&default_style);

        write!(handle, "{}{}", separator, style.paint(comp_str))?;

        // Determine separator to print before next component.
        separator = match component {
            // Prefix needs no separator, as it is always followed by RootDir.
            Component::Prefix(_) => String::new(),
            // RootDir is already a separator.
            Component::RootDir => String::new(),
            // Everything else uses a separator that is painted the same way as the component.
            _ => style.paint(path::MAIN_SEPARATOR.to_string()).to_string(),
        };
    }

    if config.null_separator {
        write!(handle, "\0")
    } else {
        writeln!(handle, "")
    }
}

fn print_entry_uncolorized(path: &Path, config: &FdOptions) -> io::Result<()> {
    let separator = if config.null_separator { "\0" } else { "\n" };

    let path_str = path.to_string_lossy();
    write!(&mut io::stdout(), "{}{}", path_str, separator)
}

fn get_path_style<'a>(path: &Path, ls_colors: &'a LsColors) -> Option<&'a ansi_term::Style> {
    if path.symlink_metadata()
        .map(|md| md.file_type().is_symlink())
        .unwrap_or(false)
    {
        return Some(&ls_colors.symlink);
    }

    let metadata = path.metadata();

    if metadata.as_ref().map(|md| md.is_dir()).unwrap_or(false) {
        Some(&ls_colors.directory)
    } else if metadata.map(|md| is_executable(&md)).unwrap_or(false) {
        Some(&ls_colors.executable)
    } else if let Some(filename_style) =
        path.file_name().and_then(|n| n.to_str()).and_then(|n| {
            ls_colors.filenames.get(n)
        })
    {
        Some(filename_style)
    } else if let Some(extension_style) =
        path.extension().and_then(|e| e.to_str()).and_then(|e| {
            ls_colors.extensions.get(e)
        })
    {
        Some(extension_style)
    } else {
        None
    }
}

#[cfg(unix)]
fn is_executable(md: &fs::Metadata) -> bool {
    md.permissions().mode() & 0o111 != 0
}

#[cfg(windows)]
fn is_executable(_: &fs::Metadata) -> bool {
    false
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use failure::Error;
use regex::Captures;

use crate::captures::CapturesExt;

pub(crate) fn gc_handler(
    sink: &mut HashMap<String, String>,
    captures: Captures,
) -> Result<(), Error> {
    let key = captures.name_ok("key")?.to_owned();
    let value = captures.name_ok("value")?.to_owned();
    let value = format!("{} ({})", value, key);

    sink.insert(key, value);

    Ok(())
}
<commit_msg>replace underscores with spaces in gc labels<commit_after>use std::collections::HashMap;

use failure::Error;
use regex::Captures;

use crate::captures::CapturesExt;

pub(crate) fn gc_handler(
    sink: &mut HashMap<String, String>,
    captures: Captures,
) -> Result<(), Error> {
    let key = captures.name_ok("key")?;
    let value = captures.name_ok("value")?;
    let value = value.replace('_', " ");
    let value = format!("{} ({})", value, key);

    sink.insert(key.to_owned(), value);

    Ok(())
}
<|endoftext|>


<commit_before>use std::mem;

use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_ATOM_EXT: u8 = 115;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.eof() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let tag = self.eat_u8()?;
        if tag == SMALL_INTEGER_EXT {
            self.small_integer()
        } else if tag == INTEGER_EXT {
            self.integer()
        } else if tag == FLOAT_EXT {
            self.old_float()
        } else if tag == NEW_FLOAT_EXT {
            self.new_float()
        } else if tag == ATOM_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom(len)
        } else if tag == SMALL_ATOM_EXT {
            let len = self.eat_u8()? as usize;
            self.atom(len)
        } else if tag == ATOM_UTF8_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_ATOM_UTF8_EXT {
            let len = self.eat_u8()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_TUPLE_EXT {
            let len = self.eat_u8()? as usize;
            self.tuple(len)
        } else if tag == LARGE_TUPLE_EXT {
            let len = self.eat_u32_be()? as usize;
            self.tuple(len)
        } else if tag == NIL_EXT {
            Ok(BertTerm::List(vec![]))
        } else if tag == LIST_EXT {
            self.list()
        } else if tag == STRING_EXT {
            self.string()
        } else if tag == BINARY_EXT {
            self.binary()
        } else if tag == SMALL_BIG_EXT {
            let len = self.eat_u8()?;
            self.bigint(len as usize)
        } else if tag == LARGE_BIG_EXT {
            let len = self.eat_u32_be()?;
            self.bigint(len as usize)
        } else {
            Err(BertError::InvalidTag(offset, tag))
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        self.peek_at(self.pos)
    }

    fn peek_at(&self, offset: usize) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(offset));
        } else {
            return Ok(self.contents[offset]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<commit_msg>Replace statics with consts<commit_after>use std::mem;

use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

const BERT_MAGIC_NUMBER: u8 = 131;
const SMALL_INTEGER_EXT: u8 = 97;
const INTEGER_EXT: u8 = 98;
const FLOAT_EXT: u8 = 99;
const ATOM_EXT: u8 = 100;
const SMALL_ATOM_EXT: u8 = 115;
const SMALL_TUPLE_EXT: u8 = 104;
const LARGE_TUPLE_EXT: u8 = 105;
const NIL_EXT: u8 = 106;
const STRING_EXT: u8 = 107;
const LIST_EXT: u8 = 108;
const BINARY_EXT: u8 = 109;
const SMALL_BIG_EXT: u8 = 110;
const LARGE_BIG_EXT: u8 = 111;
const ATOM_UTF8_EXT: u8 = 118;
const SMALL_ATOM_UTF8_EXT: u8 = 119;
const NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.eof() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let tag = self.eat_u8()?;
        if tag == SMALL_INTEGER_EXT {
            self.small_integer()
        } else if tag == INTEGER_EXT {
            self.integer()
        } else if tag == FLOAT_EXT {
            self.old_float()
        } else if tag == NEW_FLOAT_EXT {
            self.new_float()
        } else if tag == ATOM_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom(len)
        } else if tag == SMALL_ATOM_EXT {
            let len = self.eat_u8()? as usize;
            self.atom(len)
        } else if tag == ATOM_UTF8_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_ATOM_UTF8_EXT {
            let len = self.eat_u8()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_TUPLE_EXT {
            let len = self.eat_u8()? as usize;
            self.tuple(len)
        } else if tag == LARGE_TUPLE_EXT {
            let len = self.eat_u32_be()? as usize;
            self.tuple(len)
        } else if tag == NIL_EXT {
            Ok(BertTerm::List(vec![]))
        } else if tag == LIST_EXT {
            self.list()
        } else if tag == STRING_EXT {
            self.string()
        } else if tag == BINARY_EXT {
            self.binary()
        } else if tag == SMALL_BIG_EXT {
            let len = self.eat_u8()?;
            self.bigint(len as usize)
        } else if tag == LARGE_BIG_EXT {
            let len = self.eat_u32_be()?;
            self.bigint(len as usize)
        } else {
            Err(BertError::InvalidTag(offset, tag))
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        self.peek_at(self.pos)
    }

    fn peek_at(&self, offset: usize) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(offset));
        } else {
            return Ok(self.contents[offset]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

mod varlink_grammar {

    pub enum VType<'a> {
        Bool,
        Int8,
        UInt8,
        Int16,
        UInt16,
        Int32,
        UInt32,
        Int64,
        UInt64,
        Float32,
        Float64,
        VString,
        VTypename(&'a str),
        VStruct(Box<VStruct<'a>>),
    }

    pub struct VTypeExt<'a> {
        vtype: VType<'a>,
        nullable: bool,
        isarray: Option<Option<usize>>,
    }

    pub struct Argument<'a> {
        pub name: &'a str,
        pub vtypes : Vec<VTypeExt<'a>>,
    }

    pub struct VStruct<'a> {
        pub elts: Vec<Argument<'a>>,
    }

    pub struct Typedef<'a> {
        pub name: &'a str,
        pub vstruct : VStruct<'a>,
    }

    pub struct Method<'a> {
        pub name: &'a str,
        pub input : VStruct<'a>,
        pub output : VStruct<'a>,
    }

    enum MethodOrTypedef<'a> {
        Typedef(Typedef<'a>),
        Method(Method<'a>),
    }

    pub struct Interface<'a> {
        pub name: &'a str,
        pub methods: Vec<Method<'a>>,
        pub typedefs: Vec<Typedef<'a>>,
    }

    use std::fmt;

    impl<'a> fmt::Display for VType<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                VType::Bool => write!(f, "bool"),
                VType::Int8 => write!(f, "int8"),
                VType::UInt8 => write!(f, "uint8"),
                VType::Int16 => write!(f, "int16"),
                VType::UInt16 => write!(f, "uint16"),
                VType::Int32 => write!(f, "int32"),
                VType::UInt32 => write!(f, "uint32"),
                VType::Int64 => write!(f, "int64"),
                VType::UInt64 => write!(f, "uint64"),
                VType::Float32 => write!(f, "float32"),
                VType::Float64 => write!(f, "float64"),
                VType::VString => write!(f, "string"),
                VType::VTypename(ref s) => write!(f, "{}", s),
                VType::VStruct(ref v) => write!(f, "{}", v),
            }
        }
    }

    impl<'a> fmt::Display for VTypeExt<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.vtype)?;
            if let Some(t) = self.isarray {
                match t {
                    Some(v) => write!(f, "[{}]", v)?,
                    None    => write!(f, "[]")?,
                }
            }
            if self.nullable {
                write!(f, "?")
            } else {
                Ok(())
            }
        }
    }

    impl<'a> fmt::Display for Argument<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            if self.vtypes.len() == 1 {
                write!(f, "{}: {}", self.name, self.vtypes[0])?;
            } else {
                let mut iter = self.vtypes.iter();
                if let Some(fst) = iter.next() {
                    write!(f, "{}: {}", self.name, fst)?;
                    for elt in iter {
                        write!(f, "| {}", elt)?;
                    }
                }
            }
            Ok(())
        }
    }

    impl<'a> fmt::Display for VStruct<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "(")?;
            let mut iter = self.elts.iter();
            if let Some(fst) = iter.next() {
                write!(f, "{}", fst)?;
                for elt in iter {
                    write!(f, ", {}", elt)?;
                }
            }
            write!(f, ")")
        }
    }

    impl<'a> fmt::Display for Interface<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{} {{\n", self.name)?;
            for t in &self.typedefs {
                write!(f, "  type {} {};\n", t.name, t.vstruct)?;
            }
            for m in &self.methods {
                write!(f, "  {}{} -> {};\n", m.name, m.input, m.output)?;
            }
            write!(f, "}}\n")
        }
    }

    impl<'a> Interface<'a> {
        fn from_token(n: &'a str, ts: Vec<Typedef<'a>>, m: Method<'a>, mt: Vec<MethodOrTypedef<'a>>) -> Interface<'a> {
            let mut i = Interface { name: n, methods: Vec::new(), typedefs: Vec::new() };

            i.methods.push(m);

            for o in mt {
                match o {
                    MethodOrTypedef::Method(m) => i.methods.push(m),
                    MethodOrTypedef::Typedef(t) => i.typedefs.push(t)
                };
            }

            for t in ts {
                i.typedefs.push(t);
            }

            return i;
        }
    }

    include!(concat!(env!("OUT_DIR"), "/varlink_grammar.rs"));
}

#[cfg(test)]
use self::varlink_grammar::*;

#[test]
fn test_standard() {
    let ifaces = interfaces("
/**
 * The Varlink Service Interface is added to every varlink service. It provides
 * the Introspect method to be called by a client to retrieve the bootstrap
 * information from a service.
 */
org.varlink.service {
  type Type (name: string, typestring: string)
  type Method (
    name: string,
    monitor: bool,
    type_in: string,
    type_out: string
  )
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
  type InterfaceDescription (
    description: string,
    types: string[],
    methods: string[]
  )

  /**
   * Returns the machine readable information about a service. It contains the service
   * name, all available interfaces with their defined method calls and types.
   */
  Introspect(version: uint64) -> (name: string, interfaces: Interface[])

  /**
   * Returns the human readable description of a service.
   */
  Help() -> (
    description: string,
    properties: Property[],
    interfaces: InterfaceDescription[]
  )
}
")
        .unwrap();
    assert_eq!(ifaces[0].name, "org.varlink.service");
    assert_eq!(ifaces[0].to_string(), "org.varlink.service {
  type Type (name: string, typestring: string);
  type Method (name: string, monitor: bool, type_in: string, type_out: string);
  type Interface (name: string, types: Type[], methods: Method[]);
  type Property (key: string, value: string);
  type InterfaceDescription (description: string, types: string[], methods: string[]);
  Introspect(version: uint64) -> (name: string, interfaces: Interface[]);
  Help() -> (description: string, properties: Property[], interfaces: InterfaceDescription[]);
}
");

}

#[test]
fn test_one_method() {
    assert!(interfaces("/* comment */ foo.bar{ Foo()->() }").is_ok());
}

#[test]
fn test_one_method_no_type() {
    assert!(interfaces("foo.bar{ Foo()->(b:) }").is_err());
}

#[test]
fn test_domainnames() {
    assert!(interfaces("org.varlink.service {F()->()}").is_ok());
    assert!(interfaces("com.example.0example {F()->()}").is_ok());
    assert!(interfaces("com.example.example-dash {F()->()}").is_ok());
    assert!(interfaces("xn--lgbbat1ad8j.example.algeria {F()->()}").is_ok());
    assert!(interfaces("com.-example.leadinghyphen {F()->()}").is_err());
    assert!(interfaces("com.example-.danglinghyphen- {F()->()}").is_err());
    assert!(interfaces("Com.example.uppercase-toplevel {F()->()}").is_err());
    assert!(interfaces("Co9.exmaple.number-toplevel {F()->()}").is_err());
    assert!(interfaces("com.Example {F()->()}").is_err());
}

#[test]
fn test_no_method() {
    assert!(interfaces("
org.varlink.service {
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
}
")
        .is_err());
}

#[test]
fn test_type_no_args() {
    assert!(interfaces("foo.bar{ type I () F()->() }").is_ok());
}

#[test]
fn test_type_one_arg() {
    assert!(interfaces("foo.bar{ type I (b:bool) F()->() }").is_ok());
}

#[test]
fn test_type_one_array() {
    assert!(interfaces("foo.bar{ type I (b:bool[]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[1]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 1 ]) F()->() }").is_err());
}

#[test]
fn test_method_struct_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)[]? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional_wrong() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)?[]) -> ()}").is_err());
}

#[test]
fn test_format() {
    let i = interfaces("foo.bar{ type I (b:bool[1]) F()->() }").unwrap();
    assert_eq!(i[0].to_string(), "foo.bar {
  type I (b: bool[1]);
  F() -> ();
}
");
}

#[test]
fn test_box() {
    let i = interfaces("foo.bar{ F()->(s: (a: bool)) }").unwrap();
    println!("{}", i[0]);
    assert_eq!(i[0].to_string(), "foo.bar {
  F() -> (s: (a: bool));
}
");
}
<commit_msg>add union test<commit_after>#![allow(dead_code)]

mod varlink_grammar {

    pub enum VType<'a> {
        Bool,
        Int8,
        UInt8,
        Int16,
        UInt16,
        Int32,
        UInt32,
        Int64,
        UInt64,
        Float32,
        Float64,
        VString,
        VTypename(&'a str),
        VStruct(Box<VStruct<'a>>),
    }

    pub struct VTypeExt<'a> {
        vtype: VType<'a>,
        nullable: bool,
        isarray: Option<Option<usize>>,
    }

    pub struct Argument<'a> {
        pub name: &'a str,
        pub vtypes : Vec<VTypeExt<'a>>,
    }

    pub struct VStruct<'a> {
        pub elts: Vec<Argument<'a>>,
    }

    pub struct Typedef<'a> {
        pub name: &'a str,
        pub vstruct : VStruct<'a>,
    }

    pub struct Method<'a> {
        pub name: &'a str,
        pub input : VStruct<'a>,
        pub output : VStruct<'a>,
    }

    enum MethodOrTypedef<'a> {
        Typedef(Typedef<'a>),
        Method(Method<'a>),
    }

    pub struct Interface<'a> {
        pub name: &'a str,
        pub methods: Vec<Method<'a>>,
        pub typedefs: Vec<Typedef<'a>>,
    }

    use std::fmt;

    impl<'a> fmt::Display for VType<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                VType::Bool => write!(f, "bool"),
                VType::Int8 => write!(f, "int8"),
                VType::UInt8 => write!(f, "uint8"),
                VType::Int16 => write!(f, "int16"),
                VType::UInt16 => write!(f, "uint16"),
                VType::Int32 => write!(f, "int32"),
                VType::UInt32 => write!(f, "uint32"),
                VType::Int64 => write!(f, "int64"),
                VType::UInt64 => write!(f, "uint64"),
                VType::Float32 => write!(f, "float32"),
                VType::Float64 => write!(f, "float64"),
                VType::VString => write!(f, "string"),
                VType::VTypename(ref s) => write!(f, "{}", s),
                VType::VStruct(ref v) => write!(f, "{}", v),
            }
        }
    }

    impl<'a> fmt::Display for VTypeExt<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.vtype)?;
            if let Some(t) = self.isarray {
                match t {
                    Some(v) => write!(f, "[{}]", v)?,
                    None    => write!(f, "[]")?,
                }
            }
            if self.nullable {
                write!(f, "?")
            } else {
                Ok(())
            }
        }
    }

    impl<'a> fmt::Display for Argument<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            if self.vtypes.len() == 1 {
                write!(f, "{}: {}", self.name, self.vtypes[0])?;
            } else {
                let mut iter = self.vtypes.iter();
                if let Some(fst) = iter.next() {
                    write!(f, "{}: {}", self.name, fst)?;
                    for elt in iter {
                        write!(f, " | {}", elt)?;
                    }
                }
            }
            Ok(())
        }
    }

    impl<'a> fmt::Display for VStruct<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "(")?;
            let mut iter = self.elts.iter();
            if let Some(fst) = iter.next() {
                write!(f, "{}", fst)?;
                for elt in iter {
                    write!(f, ", {}", elt)?;
                }
            }
            write!(f, ")")
        }
    }

    impl<'a> fmt::Display for Interface<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{} {{\n", self.name)?;
            for t in &self.typedefs {
                write!(f, "  type {} {};\n", t.name, t.vstruct)?;
            }
            for m in &self.methods {
                write!(f, "  {}{} -> {};\n", m.name, m.input, m.output)?;
            }
            write!(f, "}}\n")
        }
    }

    impl<'a> Interface<'a> {
        fn from_token(n: &'a str, ts: Vec<Typedef<'a>>, m: Method<'a>, mt: Vec<MethodOrTypedef<'a>>) -> Interface<'a> {
            let mut i = Interface { name: n, methods: Vec::new(), typedefs: Vec::new() };

            i.methods.push(m);

            for o in mt {
                match o {
                    MethodOrTypedef::Method(m) => i.methods.push(m),
                    MethodOrTypedef::Typedef(t) => i.typedefs.push(t)
                };
            }

            for t in ts {
                i.typedefs.push(t);
            }

            return i;
        }
    }

    include!(concat!(env!("OUT_DIR"), "/varlink_grammar.rs"));
}

#[cfg(test)]
use self::varlink_grammar::*;

#[test]
fn test_standard() {
    let ifaces = interfaces("
/**
 * The Varlink Service Interface is added to every varlink service. It provides
 * the Introspect method to be called by a client to retrieve the bootstrap
 * information from a service.
 */
org.varlink.service {
  type Type (name: string, typestring: string)
  type Method (
    name: string,
    monitor: bool,
    type_in: string,
    type_out: string
  )
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
  type InterfaceDescription (
    description: string,
    types: string[],
    methods: string[]
  )

  /**
   * Returns the machine readable information about a service. It contains the service
   * name, all available interfaces with their defined method calls and types.
   */
  Introspect(version: uint64) -> (name: string, interfaces: Interface[])

  /**
   * Returns the human readable description of a service.
   */
  Help() -> (
    description: string,
    properties: Property[],
    interfaces: InterfaceDescription[]
  )
}
")
        .unwrap();
    assert_eq!(ifaces[0].name, "org.varlink.service");
    assert_eq!(ifaces[0].to_string(), "org.varlink.service {
  type Type (name: string, typestring: string);
  type Method (name: string, monitor: bool, type_in: string, type_out: string);
  type Interface (name: string, types: Type[], methods: Method[]);
  type Property (key: string, value: string);
  type InterfaceDescription (description: string, types: string[], methods: string[]);
  Introspect(version: uint64) -> (name: string, interfaces: Interface[]);
  Help() -> (description: string, properties: Property[], interfaces: InterfaceDescription[]);
}
");

}

#[test]
fn test_one_method() {
    assert!(interfaces("/* comment */ foo.bar{ Foo()->() }").is_ok());
}

#[test]
fn test_one_method_no_type() {
    assert!(interfaces("foo.bar{ Foo()->(b:) }").is_err());
}

#[test]
fn test_domainnames() {
    assert!(interfaces("org.varlink.service {F()->()}").is_ok());
    assert!(interfaces("com.example.0example {F()->()}").is_ok());
    assert!(interfaces("com.example.example-dash {F()->()}").is_ok());
    assert!(interfaces("xn--lgbbat1ad8j.example.algeria {F()->()}").is_ok());
    assert!(interfaces("com.-example.leadinghyphen {F()->()}").is_err());
    assert!(interfaces("com.example-.danglinghyphen- {F()->()}").is_err());
    assert!(interfaces("Com.example.uppercase-toplevel {F()->()}").is_err());
    assert!(interfaces("Co9.exmaple.number-toplevel {F()->()}").is_err());
    assert!(interfaces("com.Example {F()->()}").is_err());
}

#[test]
fn test_no_method() {
    assert!(interfaces("
org.varlink.service {
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
}
")
        .is_err());
}

#[test]
fn test_type_no_args() {
    assert!(interfaces("foo.bar{ type I () F()->() }").is_ok());
}

#[test]
fn test_type_one_arg() {
    assert!(interfaces("foo.bar{ type I (b:bool) F()->() }").is_ok());
}

#[test]
fn test_type_one_array() {
    assert!(interfaces("foo.bar{ type I (b:bool[]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[1]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 1 ]) F()->() }").is_err());
}

#[test]
fn test_method_struct_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)[]? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional_wrong() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)?[]) -> ()}").is_err());
}

#[test]
fn test_format() {
    let i = interfaces("foo.bar{ type I (b:bool[1]) F()->() }").unwrap();
    assert_eq!(i[0].to_string(), "foo.bar {
  type I (b: bool[1]);
  F() -> ();
}
");
}

#[test]
fn test_union() {
    let i = interfaces("foo.bar{ F()->(s: (a: bool, b: int64), u: bool|int64) }").unwrap();
    println!("{}", i[0]);
    assert_eq!(i[0].to_string(), "foo.bar {
  F() -> (s: (a: bool, b: int64), u: bool | int64);
}
");
}
<|endoftext|>