<commit_before>#[macro_use]
extern crate log;

extern crate regex;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use regex::Regex;
use std::io::Write;
use std::cmp;

mod error;
mod evaluator;
mod event;
mod inner_tokenizer;
mod sass;
mod substituter;
mod tokenizer;
mod tokenizer_utils;
mod value_tokenizer;

use error::{SassError, Result};
use tokenizer::Tokenizer;

fn resolve_imports(inputpath: &PathBuf) -> Result<String> {
    let mut file = try!(File::open(&inputpath));
    let mut sass = String::new();

    try!(file.read_to_string(&mut sass));

    let mut imports_resolved = String::new();
    for line in sass.split("\n") {
        let re = Regex::new("@import \"([^\"]*)\";").unwrap();

        match re.captures(line) {
            Some(caps) => {
                let imported = try!(resolve_imports(&inputpath.with_file_name(caps.at(1).unwrap())));
                imports_resolved.push_str(&imported);
            },
            None => {
                imports_resolved.push_str(line);
            },
        }
        imports_resolved.push_str("\n");
    }
    Ok(imports_resolved)
}

pub fn compile<W: Write>(input_filename: &str, output: &mut W, style: &str) -> Result<()> {
    let input_path = PathBuf::from(input_filename);
    let imports_resolved = try!(resolve_imports(&input_path));
    let max_offset = imports_resolved.len();

    let mut tokenizer = Tokenizer::new(&imports_resolved);
    let style = try!(style.parse());

    match tokenizer.stream(output, style) {
        Err(sass_error) => {
            let context_start = sass_error.offset - cmp::min(sass_error.offset, 20);
            let context_end = cmp::min(sass_error.offset + 20, max_offset);
            Err(SassError {
                message: format!("{}\nAt {}: `{}`",
                    sass_error.message,
                    sass_error.offset,
                    &imports_resolved[context_start..context_end],
                ),
                ..sass_error
            })
        },
        other => other,
    }
}
<commit_msg>Instead of giving 40 bytes of context, give 1 line with byte marker<commit_after>#[macro_use]
extern crate log;

extern crate regex;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use regex::Regex;
use std::io::Write;
use std::iter;

mod error;
mod evaluator;
mod event;
mod inner_tokenizer;
mod sass;
mod substituter;
mod tokenizer;
mod tokenizer_utils;
mod value_tokenizer;

use error::{SassError, Result};
use tokenizer::Tokenizer;

fn resolve_imports(inputpath: &PathBuf) -> Result<String> {
    let mut file = try!(File::open(&inputpath));
    let mut sass = String::new();

    try!(file.read_to_string(&mut sass));

    let mut imports_resolved = String::new();
    for line in sass.split("\n") {
        let re = Regex::new("@import \"([^\"]*)\";").unwrap();

        match re.captures(line) {
            Some(caps) => {
                let imported = try!(resolve_imports(&inputpath.with_file_name(caps.at(1).unwrap())));
                imports_resolved.push_str(&imported);
            },
            None => {
                imports_resolved.push_str(line);
            },
        }
        imports_resolved.push_str("\n");
    }
    Ok(imports_resolved)
}

pub fn compile<W: Write>(input_filename: &str, output: &mut W, style: &str) -> Result<()> {
    let input_path = PathBuf::from(input_filename);
    let imports_resolved = try!(resolve_imports(&input_path));
    let max_offset = imports_resolved.len();

    let mut tokenizer = Tokenizer::new(&imports_resolved);
    let style = try!(style.parse());

    match tokenizer.stream(output, style) {
        Err(sass_error) => {
            let before_error = &imports_resolved[0..sass_error.offset];
            let after_error = &imports_resolved[sass_error.offset..];

            let context_start = before_error
                .as_bytes()
                .iter()
                .rposition(|&c| c == b'\n')
                .unwrap_or(0);
            let context_end = after_error
                .as_bytes()
                .iter()
                .position(|&c| c == b'\n')
                .unwrap_or(max_offset);

            Err(SassError {
                message: format!("{}\nOn line {}:\n{}\n{}^",
                    sass_error.message,
                    before_error.split("\n").collect::<Vec<_>>().len(),
                    &imports_resolved[context_start..context_end + sass_error.offset],
                    iter::repeat(" ")
                         .take(sass_error.offset - context_start)
                         .collect::<Vec<_>>()
                         .join(""),
                ),
                ..sass_error
            })
        },
        other => other,
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};

static LOOP_SET_FD: u64 = 0x4C00;
static LOOP_CLR_FD: u64 = 0x4C01;
static LOOP_SET_STATUS64: u64 = 0x4C04;
static LOOP_CTL_GET_FREE: u64 = 0x4C82;

const LOOP_PREFIX: &'static str = "/dev/loop";

#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    pub fn open(dev_file: &str) -> io::Result<LoopControl> {
        Ok(LoopControl { dev_file: try!(OpenOptions::new().read(true).write(true).open(dev_file)) })
    }

    // Finds and returns the next availble loop device
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result: i32;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let path = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(LoopDevice { device: try!(OpenOptions::new().read(true).write(true).open(path)) })
        }
    }
}

#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

#[repr(C)]
pub struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

use std::default::Default;

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

impl LoopDevice {
    // Attach a loop device to a file.
    pub fn attach(&mut self, backing_file: &str, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach backing_file to device
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD,
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64,
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    // Detach a loop device from its backing file.
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD, 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}
<commit_msg>Inital implmentation of LoopDevice::new<commit_after>extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};

static LOOP_SET_FD: u64 = 0x4C00;
static LOOP_CLR_FD: u64 = 0x4C01;
static LOOP_SET_STATUS64: u64 = 0x4C04;
static LOOP_CTL_GET_FREE: u64 = 0x4C82;

const LOOP_PREFIX: &'static str = "/dev/loop";

#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    pub fn open(dev_file: &str) -> io::Result<LoopControl> {
        Ok(LoopControl { dev_file: try!(OpenOptions::new().read(true).write(true).open(dev_file)) })
    }

    // Finds and returns the next availble loop device
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result: i32;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let path = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(LoopDevice { device: try!(OpenOptions::new().read(true).write(true).open(path)) })
        }
    }
}

#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

#[repr(C)]
pub struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

use std::default::Default;

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

impl LoopDevice {
    pub fn new(dev: &str) -> io::Result<LoopDevice> {
        // TODO check dev is actually a loop device
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    // Attach a loop device to a file.
    pub fn attach(&mut self, backing_file: &str, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach backing_file to device
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD,
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64,
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    // Detach a loop device from its backing file.
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD, 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate quickcheck;

pub mod multikey_quicksort{

    pub fn sort(vec: &mut [String]){
        sort_req(vec, 0);
    }

    fn sort_req(vec: &mut [String], depth: usize){
        if vec.len() <= 50 {//|| depth > 2 {
            vec.sort_unstable();
            return;
        }
        let mut counts = [0usize;257];
        for elem in vec.iter(){
            let radix_val = radix_for_str(elem, depth);
            counts[radix_val as usize] += 1;
        }
        let mut sum = 0usize;
        let mut offsets = [0usize;257];
        for i in 0..256 {
            offsets[i as usize] = sum;
            sum += counts[i as usize];
        }
        let mut next_free = offsets.clone();

        let mut block = 0usize;
        let mut i = 0usize;
        while block < 255 {
            if i >= offsets[block + 1] as usize {
                block += 1;
            }
            else{
                let radix_val = radix_for_str(&vec[i as usize], depth) as usize;
                if radix_val == block {
                    i+=1;
                }
                else {
                    vec.swap(i as usize, next_free[radix_val] as usize);
                    next_free[radix_val] += 1;
                }
            }
        }
        for i in 0..254 {
            sort_req(&mut vec[offsets[i as usize] as usize..offsets[i as usize+1] as usize], depth+1);
        }
        sort_req(&mut vec[offsets[254]..], depth+1);
    }

    fn radix_for_str(s: &str, d: usize) -> u16{
        if s.as_bytes().len() > d{
            (s.as_bytes()[d] as u16 + 1)
        }
        else{
            0
        }
    }
}

#[cfg(test)]
mod tests {

    use multikey_quicksort;
    use quickcheck::QuickCheck;
    use test::Bencher;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use rand::{self,Rng};

    #[test]
    fn sorts_same_as_unstable() {
        fn compare_sort(mut strings: Vec<String>) -> bool {
            let mut copy = strings.clone();
            copy.sort_unstable();
            multikey_quicksort::sort(&mut strings);
            strings == copy
        };
        QuickCheck::new()
            .tests(10000)
            .quickcheck(compare_sort as fn(Vec<String>) -> bool);
    }

    fn strings_en() -> Vec<String> {
        let f = File::open("/usr/share/dict/american-english").unwrap();
        let b = BufReader::new(f);
        let mut strings = b.lines().map(|l|l.unwrap()).collect::<Vec<String>>();
        let mut rng = rand::thread_rng();
        rng.shuffle(&mut strings);
        strings.into_iter().take(100000).collect::<Vec<String>>()
    }

    #[bench]
    fn std_sort(b: &mut Bencher) {
        let strings =strings_en();
        b.iter(|| strings.clone().sort_unstable())
    }

    #[bench]
    fn af_sort(b: &mut Bencher) {
        let strings = strings_en();
        b.iter(|| multikey_quicksort::sort(&mut strings.clone()))
    }

}
<commit_msg>Properly rename module to be same name as crate.<commit_after>#![feature(test)]
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate quickcheck;

pub mod afsort{

    pub fn sort(vec: &mut [String]){
        sort_req(vec, 0);
    }

    fn sort_req(vec: &mut [String], depth: usize){
        if vec.len() <= 50 {//|| depth > 2 {
            vec.sort_unstable();
            return;
        }
        let mut counts = [0usize;257];
        for elem in vec.iter(){
            let radix_val = radix_for_str(elem, depth);
            counts[radix_val as usize] += 1;
        }
        let mut sum = 0usize;
        let mut offsets = [0usize;257];
        for i in 0..256 {
            offsets[i as usize] = sum;
            sum += counts[i as usize];
        }
        let mut next_free = offsets.clone();

        let mut block = 0usize;
        let mut i = 0usize;
        while block < 255 {
            if i >= offsets[block + 1] as usize {
                block += 1;
            }
            else{
                let radix_val = radix_for_str(&vec[i as usize], depth) as usize;
                if radix_val == block {
                    i+=1;
                }
                else {
                    vec.swap(i as usize, next_free[radix_val] as usize);
                    next_free[radix_val] += 1;
                }
            }
        }
        for i in 0..254 {
            sort_req(&mut vec[offsets[i as usize] as usize..offsets[i as usize+1] as usize], depth+1);
        }
        sort_req(&mut vec[offsets[254]..], depth+1);
    }

    fn radix_for_str(s: &str, d: usize) -> u16{
        if s.as_bytes().len() > d{
            (s.as_bytes()[d] as u16 + 1)
        }
        else{
            0
        }
    }
}

#[cfg(test)]
mod tests {

    use afsort;
    use quickcheck::QuickCheck;
    use test::Bencher;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use rand::{self,Rng};

    #[test]
    fn sorts_same_as_unstable() {
        fn compare_sort(mut strings: Vec<String>) -> bool {
            let mut copy = strings.clone();
            copy.sort_unstable();
            afsort::sort(&mut strings);
            strings == copy
        };
        QuickCheck::new()
            .tests(10000)
            .quickcheck(compare_sort as fn(Vec<String>) -> bool);
    }

    fn strings_en() -> Vec<String> {
        let f = File::open("/usr/share/dict/american-english").unwrap();
        let b = BufReader::new(f);
        let mut strings = b.lines().map(|l|l.unwrap()).collect::<Vec<String>>();
        let mut rng = rand::thread_rng();
        rng.shuffle(&mut strings);
        strings.into_iter().take(100000).collect::<Vec<String>>()
    }

    #[bench]
    fn std_sort(b: &mut Bencher) {
        let strings =strings_en();
        b.iter(|| strings.clone().sort_unstable())
    }

    #[bench]
    fn af_sort(b: &mut Bencher) {
        let strings = strings_en();
        b.iter(|| afsort::sort(&mut strings.clone()))
    }

}
<|endoftext|>


<commit_before>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.12")]
#![deny(missing_docs)]
#![deny(clippy::all, clippy::pedantic)]
// Suppressed clippy_pedantic lints
#![allow(
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::use_self,
    // code is acceptable
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    // not practical
    clippy::indexing_slicing,
    clippy::missing_docs_in_private_items,
    // not stable
    clippy::checked_conversions,
    clippy::empty_enum,
    // meh, some things won't fail
    clippy::result_unwrap_used,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
pub mod mapping;
mod number;
mod path;
mod ser;
mod value;
<commit_msg>Update name of renamed unwrap_used lint<commit_after>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.12")]
#![deny(missing_docs)]
#![deny(clippy::all, clippy::pedantic)]
// Suppressed clippy_pedantic lints
#![allow(
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::use_self,
    // code is acceptable
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    // not practical
    clippy::indexing_slicing,
    clippy::missing_docs_in_private_items,
    // not stable
    clippy::checked_conversions,
    clippy::empty_enum,
    // meh, some things won't fail
    clippy::unwrap_used,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
pub mod mapping;
mod number;
mod path;
mod ser;
mod value;
<|endoftext|>


<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use bindings::{
    loop_info64, LOOP_CLR_FD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_FD, LOOP_SET_STATUS64,
};
use libc::{c_int, ioctl};
use std::{
    default::Default,
    fs::{File, Metadata, OpenOptions},
    io,
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(non_snake_case)]
mod bindings {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(not(target_os = "android"))]
type IoctlRequest = libc::c_ulong;
#[cfg(target_os = "android")]
type IoctlRequest = libc::c_int;

const LOOP_CONTROL: &str = "/dev/loop-control";
#[cfg(not(target_os = "android"))]
const LOOP_PREFIX: &str = "/dev/loop";
#[cfg(target_os = "android")]
const LOOP_PREFIX: &str = "/dev/block/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(
                self.dev_file.as_raw_fd() as c_int,
                LOOP_CTL_GET_FREE as IoctlRequest,
            )
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

impl AsRawFd for LoopControl {
    fn as_raw_fd(&self) -> RawFd {
        self.dev_file.as_raw_fd()
    }
}

impl IntoRawFd for LoopControl {
    fn into_raw_fd(self) -> RawFd {
        self.dev_file.into_raw_fd()
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl IntoRawFd for LoopDevice {
    fn into_raw_fd(self) -> RawFd {
        self.device.into_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop3").unwrap();
    /// ld.with().part_scan(true).attach("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&mut self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = loop_info64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info64.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: loop_info64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD as IoctlRequest,
                bf.as_raw_fd() as c_int,
            )
        })?;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64 as IoctlRequest,
                &info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Get the device metadata
    pub fn metadata(&self) -> io::Result<Metadata> {
        self.device.metadata()
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_CLR_FD as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }
}

/// Used to set options when attaching a device. Created with [LoopDevice::with()].
///
/// # Examples
///
/// Enable partition scanning on attach:
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop6").unwrap();
/// ld.with()
///     .part_scan(true)
///     .attach("test.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
///
/// A 1MiB slice of the file located at 1KiB into the file.
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop7").unwrap();
/// ld.with()
///     .offset(1024*1024)
///     .size_limit(1024*1024*1024)
///     .attach("test.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
pub struct AttachOptions<'d> {
    device: &'d mut LoopDevice,
    info: loop_info64,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<commit_msg>Replace LoopDevice::metadata with major and minor<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use bindings::{
    loop_info64, LOOP_CLR_FD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_FD, LOOP_SET_STATUS64,
};
use libc::{c_int, ioctl};
use std::{
    default::Default,
    fs::{File, OpenOptions},
    io,
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(non_snake_case)]
mod bindings {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(not(target_os = "android"))]
type IoctlRequest = libc::c_ulong;
#[cfg(target_os = "android")]
type IoctlRequest = libc::c_int;

const LOOP_CONTROL: &str = "/dev/loop-control";
#[cfg(not(target_os = "android"))]
const LOOP_PREFIX: &str = "/dev/loop";
#[cfg(target_os = "android")]
const LOOP_PREFIX: &str = "/dev/block/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(
                self.dev_file.as_raw_fd() as c_int,
                LOOP_CTL_GET_FREE as IoctlRequest,
            )
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

impl AsRawFd for LoopControl {
    fn as_raw_fd(&self) -> RawFd {
        self.dev_file.as_raw_fd()
    }
}

impl IntoRawFd for LoopControl {
    fn into_raw_fd(self) -> RawFd {
        self.dev_file.into_raw_fd()
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl IntoRawFd for LoopDevice {
    fn into_raw_fd(self) -> RawFd {
        self.device.into_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop3").unwrap();
    /// ld.with().part_scan(true).attach("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&mut self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = loop_info64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info64.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: loop_info64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD as IoctlRequest,
                bf.as_raw_fd() as c_int,
            )
        })?;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64 as IoctlRequest,
                &info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Get the device major number
    pub fn major(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::major(m.rdev()) as u32 })
    }

    /// Get the device major number
    pub fn minor(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::minor(m.rdev()) as u32 })
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_CLR_FD as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }
}

/// Used to set options when attaching a device. Created with [LoopDevice::with()].
///
/// # Examples
///
/// Enable partition scanning on attach:
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop6").unwrap();
/// ld.with()
///     .part_scan(true)
///     .attach("test.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
///
/// A 1MiB slice of the file located at 1KiB into the file.
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop7").unwrap();
/// ld.with()
///     .offset(1024*1024)
///     .size_limit(1024*1024*1024)
///     .attach("test.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
pub struct AttachOptions<'d> {
    device: &'d mut LoopDevice,
    info: loop_info64,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>//! Note: library usage is not semver/API-stable
//!
//! Type evolution of a websocat run:
//!
//! 1. `&str` - string as passed to command line. When it meets the list of `SpecifierClass`es, there appears:
//! 2. `Specifier` - more organized representation, may be nested. When `construct` is called, we get:
//! 3. `PeerConstructor` - a future or stream that returns one or more connections. After completion, we get one or more of:
//! 4. `Peer` - an active connection. Once we have two of them, we can start a:
//! 5. `Session` with two `Transfer`s - forward and reverse.

extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate websocket;

#[macro_use]
extern crate log;

#[macro_use]
extern crate slab_typesafe;

#[macro_use]
extern crate smart_default;

use futures::future::Future;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};

use futures::Stream;

use std::cell::RefCell;
use std::rc::Rc;
use std::str::FromStr;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

pub struct WebsocatConfiguration1 {
    pub opts: Options,
    pub addr1: String,
    pub addr2: String,
}

impl WebsocatConfiguration1 {
    pub fn parse1(self) -> Result<WebsocatConfiguration2> {
        Ok(WebsocatConfiguration2 {
            opts: self.opts,
            s1: SpecifierStack::from_str(self.addr1.as_str())?,
            s2: SpecifierStack::from_str(self.addr2.as_str())?,
        })
    }
}

pub struct WebsocatConfiguration2 {
    pub opts: Options,
    pub s1: SpecifierStack,
    pub s2: SpecifierStack,
}

impl WebsocatConfiguration2 {
    pub fn parse2(self) -> Result<WebsocatConfiguration3> {
        Ok(WebsocatConfiguration3 {
            opts: self.opts,
            s1: Specifier::from_stack(&self.s1)?,
            s2: Specifier::from_stack(&self.s2)?,
        })
    }
}

pub struct WebsocatConfiguration3 {
    pub opts: Options,
    pub s1: Rc<Specifier>,
    pub s2: Rc<Specifier>,
}

impl WebsocatConfiguration3 {
    pub fn serve<OE>(
        self,
        h: Handle,
        onerror: std::rc::Rc<OE>,
    ) -> Box<Future<Item = (), Error = ()>>
    where
        OE: Fn(Box<std::error::Error>) -> () + 'static,
    {
        serve(h, self.s1, self.s2, self.opts, onerror)
    }
}

pub mod options;
pub use options::Options;

#[derive(Default)]
pub struct ProgramState {
    #[cfg(all(unix, feature = "unix_stdio"))]
    stdio: stdio_peer::GlobalState,

    reuser: primitive_reuse_peer::GlobalState,
    reuser2: broadcast_reuse_peer::GlobalState,
}

/// Some information passed from the left specifier Peer to the right
#[derive(Default, Clone)]
pub struct LeftSpecToRightSpec {
    /// URI the client requested when connecting to WebSocket
    uri: Option<String>,
    /// Address:port of connecting client, if it is TCP
    client_addr: Option<String>,
}

pub type L2rWriter = Rc<RefCell<LeftSpecToRightSpec>>;
pub type L2rReader = Rc<        LeftSpecToRightSpec >;

#[derive(Clone)]
pub enum L2rUser {
    FillIn  (L2rWriter),
    ReadFrom(L2rReader),
}

pub struct Peer(Box<AsyncRead>, Box<AsyncWrite>);

pub type BoxedNewPeerFuture = Box<Future<Item = Peer, Error = Box<std::error::Error>>>;
pub type BoxedNewPeerStream = Box<Stream<Item = Peer, Error = Box<std::error::Error>>>;

#[macro_use]
pub mod specifier;
pub use specifier::{
    ClassMessageBoundaryStatus, ClassMulticonnectStatus, ConstructParams, Specifier,
    SpecifierClass, SpecifierStack,
};

#[macro_use]
pub mod all_peers;

pub mod lints;
mod my_copy;

pub use util::{brokenpipe, io_other_error, wouldblock};

#[cfg(all(unix, feature = "unix_stdio"))]
pub mod stdio_peer;

pub mod file_peer;
pub mod mirror_peer;
pub mod net_peer;
pub mod stdio_threaded_peer;
pub mod trivial_peer;
pub mod ws_client_peer;
pub mod ws_peer;
pub mod ws_server_peer;

#[cfg(feature = "tokio-process")]
pub mod process_peer;

#[cfg(unix)]
pub mod unix_peer;

pub mod broadcast_reuse_peer;
pub mod line_peer;
pub mod jsonrpc_peer;
pub mod primitive_reuse_peer;
pub mod reconnect_peer;

pub mod specparse;

pub type PeerOverlay = Rc<Fn(Peer, L2rUser) -> BoxedNewPeerFuture>;

pub enum PeerConstructor {
    ServeOnce(BoxedNewPeerFuture),
    ServeMultipleTimes(BoxedNewPeerStream),
    Overlay1(BoxedNewPeerFuture, PeerOverlay),
    OverlayM(BoxedNewPeerStream, PeerOverlay),
}

pub mod util;
pub use util::{box_up_err, multi, once, peer_err, peer_err_s, peer_strerr, simple_err};

pub mod readdebt;

pub use specparse::spec;

pub struct Transfer {
    from: Box<AsyncRead>,
    to: Box<AsyncWrite>,
}
pub struct Session(Transfer, Transfer, Rc<Options>);

pub mod sessionserve;
pub use sessionserve::serve;
<commit_msg>Update crate-level doc<commit_after>//! Note: library usage is not semver/API-stable
//!
//! Type evolution of a websocat run:
//!
//! 1. `&str` - string as passed to command line. When it meets the list of `SpecifierClass`es, there appears:
//! 2. `SpecifierStack` - specifier class, final string argument and vector of overlays.
//! 3. `Specifier` - more rigid version of SpecifierStack, with everything parsable parsed. May be nested. When `construct` is called, we get:
//! 4. `PeerConstructor` - a future or stream that returns one or more connections. After completion, we get one or more of:
//! 5. `Peer` - an active connection. Once we have two of them, we can start a:
//! 6. `Session` with two `Transfer`s - forward and reverse.

extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate websocket;

#[macro_use]
extern crate log;

#[macro_use]
extern crate slab_typesafe;

#[macro_use]
extern crate smart_default;

use futures::future::Future;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};

use futures::Stream;

use std::cell::RefCell;
use std::rc::Rc;
use std::str::FromStr;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

pub struct WebsocatConfiguration1 {
    pub opts: Options,
    pub addr1: String,
    pub addr2: String,
}

impl WebsocatConfiguration1 {
    pub fn parse1(self) -> Result<WebsocatConfiguration2> {
        Ok(WebsocatConfiguration2 {
            opts: self.opts,
            s1: SpecifierStack::from_str(self.addr1.as_str())?,
            s2: SpecifierStack::from_str(self.addr2.as_str())?,
        })
    }
}

pub struct WebsocatConfiguration2 {
    pub opts: Options,
    pub s1: SpecifierStack,
    pub s2: SpecifierStack,
}

impl WebsocatConfiguration2 {
    pub fn parse2(self) -> Result<WebsocatConfiguration3> {
        Ok(WebsocatConfiguration3 {
            opts: self.opts,
            s1: Specifier::from_stack(&self.s1)?,
            s2: Specifier::from_stack(&self.s2)?,
        })
    }
}

pub struct WebsocatConfiguration3 {
    pub opts: Options,
    pub s1: Rc<Specifier>,
    pub s2: Rc<Specifier>,
}

impl WebsocatConfiguration3 {
    pub fn serve<OE>(
        self,
        h: Handle,
        onerror: std::rc::Rc<OE>,
    ) -> Box<Future<Item = (), Error = ()>>
    where
        OE: Fn(Box<std::error::Error>) -> () + 'static,
    {
        serve(h, self.s1, self.s2, self.opts, onerror)
    }
}

pub mod options;
pub use options::Options;

#[derive(Default)]
pub struct ProgramState {
    #[cfg(all(unix, feature = "unix_stdio"))]
    stdio: stdio_peer::GlobalState,

    reuser: primitive_reuse_peer::GlobalState,
    reuser2: broadcast_reuse_peer::GlobalState,
}

/// Some information passed from the left specifier Peer to the right
#[derive(Default, Clone)]
pub struct LeftSpecToRightSpec {
    /// URI the client requested when connecting to WebSocket
    uri: Option<String>,
    /// Address:port of connecting client, if it is TCP
    client_addr: Option<String>,
}

pub type L2rWriter = Rc<RefCell<LeftSpecToRightSpec>>;
pub type L2rReader = Rc<        LeftSpecToRightSpec >;

#[derive(Clone)]
pub enum L2rUser {
    FillIn  (L2rWriter),
    ReadFrom(L2rReader),
}

pub struct Peer(Box<AsyncRead>, Box<AsyncWrite>);

pub type BoxedNewPeerFuture = Box<Future<Item = Peer, Error = Box<std::error::Error>>>;
pub type BoxedNewPeerStream = Box<Stream<Item = Peer, Error = Box<std::error::Error>>>;

#[macro_use]
pub mod specifier;
pub use specifier::{
    ClassMessageBoundaryStatus, ClassMulticonnectStatus, ConstructParams, Specifier,
    SpecifierClass, SpecifierStack,
};

#[macro_use]
pub mod all_peers;

pub mod lints;
mod my_copy;

pub use util::{brokenpipe, io_other_error, wouldblock};

#[cfg(all(unix, feature = "unix_stdio"))]
pub mod stdio_peer;

pub mod file_peer;
pub mod mirror_peer;
pub mod net_peer;
pub mod stdio_threaded_peer;
pub mod trivial_peer;
pub mod ws_client_peer;
pub mod ws_peer;
pub mod ws_server_peer;

#[cfg(feature = "tokio-process")]
pub mod process_peer;

#[cfg(unix)]
pub mod unix_peer;

pub mod broadcast_reuse_peer;
pub mod line_peer;
pub mod jsonrpc_peer;
pub mod primitive_reuse_peer;
pub mod reconnect_peer;

pub mod specparse;

pub type PeerOverlay = Rc<Fn(Peer, L2rUser) -> BoxedNewPeerFuture>;

pub enum PeerConstructor {
    ServeOnce(BoxedNewPeerFuture),
    ServeMultipleTimes(BoxedNewPeerStream),
    Overlay1(BoxedNewPeerFuture, PeerOverlay),
    OverlayM(BoxedNewPeerStream, PeerOverlay),
}

pub mod util;
pub use util::{box_up_err, multi, once, peer_err, peer_err_s, peer_strerr, simple_err};

pub mod readdebt;

pub use specparse::spec;

pub struct Transfer {
    from: Box<AsyncRead>,
    to: Box<AsyncWrite>,
}
pub struct Session(Transfer, Transfer, Rc<Options>);

pub mod sessionserve;
pub use sessionserve::serve;
<|endoftext|>


<commit_before>#![crate_type = "rlib"]
#![feature(macro_rules,globs)]

#[macro_export]
macro_rules! monad(
    ($m:ident {
        let $p:pat <- $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        $m::mbind($e,|$p| {
            monad!($m {
                $($rest)*
            } in $y)
        })
    );
    ($m:ident {
        let $p:pat = $e:expr;
        $($rest:tt)*
    } in $y:expr) => ({
        let $p = $e;
        monad!($m { $($rest)* } in $y)
    });
    ($m:ident {
        $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        monad!($m { let _ <- $e; $($rest)* } in $y)
    );
    ($m:ident {
        $e:expr
    } in $y:expr) => (
        monad!($m { let _ <- $e; } in $y)
    );
    ($m:ident { } in $y:expr) => ($m::mpure($y));
)

pub struct OptionMonad;

impl OptionMonad {
    pub fn mpure<T>(value: T) -> Option<T> { Some(value) }
    pub fn mbind<T,U>(value: Option<T>, func: |T| -> Option<U>) -> Option<U> {
        match value {
            Some(v) => func(v),
            None => None
        }
    }
}

pub struct ResultMonad;

impl ResultMonad {
    pub fn mpure<T,E>(value: T) -> Result<T,E> { Ok(value) }
    pub fn mbind<T,U,E>(value: Result<T,E>, func: |T| -> Result<U,E>) -> Result<U,E> {
        match value {
            Ok(v) => func(v),
            Err(e) => Err(e)
        }
    }
}

pub struct IterMonad;

impl IterMonad {
    pub fn mpure<T>(value: T) -> std::option::Item<T> {
        Some(value).into_iter()
    }
    pub fn mbind<T,U,I:Iterator<T>,J:Iterator<U>>(value: I, func: |T| -> J)
                                                  -> std::vec::MoveItems<U> {
        value.flat_map(func).collect::<Vec<U>>().into_iter()
    }
}

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

    #[test]
    fn option() {
        let result = monad!(OptionMonad {
            let (a,x) <- Some((2i,6i));
            let (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Some((2+3,6*7)));
    }

    #[test]
    fn option_fail() {
        let result = monad!(OptionMonad {
            let (a,x) <- None::<(int,int)>;
            let (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, None);
    }

    #[test]
    fn result() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            let (a,x) <- Ok((2i,6i));
            let (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Ok((2+3,6*7)));
    }

    #[test]
    fn result_fail() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            let (a,x) <- Err::<(int,int),()>(());
            let (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Err(()));
    }

    #[test]
    fn iter() {
        let mut result = monad!(IterMonad {
            let a <- vec![1u,2,3].into_iter();
            let b <- vec!["hello"].into_iter();
        } in (a,b));

        assert_eq!(result.collect::<Vec<(uint,&'static str)>>(),
                   vec![(1u,"hello"),(2,"hello"),(3,"hello")]);
    }

    #[test]
    fn ordinary_bindings() {
        let result = monad!(OptionMonad {
            let a = Some(5u);
            let x <- a;
            let b = Some(4u);
            let y <- b;
        } in x*y);
        assert_eq!(result, Some(20));
    }

    #[test]
    fn sequence() {
        let result = monad!(OptionMonad {
            Some(());
            let x <- Some(());
            None::<()>
        } in x);
        assert_eq!(result, None);
    }
}
<commit_msg>Remove let keyword from monadic bindings<commit_after>#![crate_type = "rlib"]
#![feature(macro_rules,globs)]

#[macro_export]
macro_rules! monad(
    ($m:ident {
        let $p:pat = $e:expr;
        $($rest:tt)*
    } in $y:expr) => ({
        let $p = $e;
        monad!($m { $($rest)* } in $y)
    });
    ($m:ident {
        $p:pat <- $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        $m::mbind($e,|$p| {
            monad!($m {
                $($rest)*
            } in $y)
        })
    );
    ($m:ident {
        $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        monad!($m { _ <- $e; $($rest)* } in $y)
    );
    ($m:ident {
        $e:expr
    } in $y:expr) => (
        monad!($m { _ <- $e; } in $y)
    );
    ($m:ident { } in $y:expr) => ($m::mpure($y));
)

pub struct OptionMonad;

impl OptionMonad {
    pub fn mpure<T>(value: T) -> Option<T> { Some(value) }
    pub fn mbind<T,U>(value: Option<T>, func: |T| -> Option<U>) -> Option<U> {
        match value {
            Some(v) => func(v),
            None => None
        }
    }
}

pub struct ResultMonad;

impl ResultMonad {
    pub fn mpure<T,E>(value: T) -> Result<T,E> { Ok(value) }
    pub fn mbind<T,U,E>(value: Result<T,E>, func: |T| -> Result<U,E>) -> Result<U,E> {
        match value {
            Ok(v) => func(v),
            Err(e) => Err(e)
        }
    }
}

pub struct IterMonad;

impl IterMonad {
    pub fn mpure<T>(value: T) -> std::option::Item<T> {
        Some(value).into_iter()
    }
    pub fn mbind<T,U,I:Iterator<T>,J:Iterator<U>>(value: I, func: |T| -> J)
                                                  -> std::vec::MoveItems<U> {
        value.flat_map(func).collect::<Vec<U>>().into_iter()
    }
}

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

    #[test]
    fn option() {
        let result = monad!(OptionMonad {
            (a,x) <- Some((2i,6i));
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Some((2+3,6*7)));
    }

    #[test]
    fn option_fail() {
        let result = monad!(OptionMonad {
            (a,x) <- None::<(int,int)>;
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, None);
    }

    #[test]
    fn result() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Ok((2i,6i));
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Ok((2+3,6*7)));
    }

    #[test]
    fn result_fail() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Err::<(int,int),()>(());
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Err(()));
    }

    #[test]
    fn iter() {
        let mut result = monad!(IterMonad {
            a <- vec![1u,2,3].into_iter();
            b <- vec!["hello"].into_iter();
        } in (a,b));

        assert_eq!(result.collect::<Vec<(uint,&'static str)>>(),
                   vec![(1u,"hello"),(2,"hello"),(3,"hello")]);
    }

    #[test]
    fn ordinary_bindings() {
        let result = monad!(OptionMonad {
            let a = Some(5u);
            x <- a;
            let b = Some(4u);
            y <- b;
        } in x*y);
        assert_eq!(result, Some(20));
    }

    #[test]
    fn sequence() {
        let result = monad!(OptionMonad {
            Some(());
            x <- Some(());
            None::<()>
        } in x);
        assert_eq!(result, None);
    }
}
<|endoftext|>


<commit_before>extern crate lmdb;
extern crate lmdb_sys;

use std::{result, str};
use std::path::Path;
use lmdb::{Transaction, Cursor, DUP_SORT, INTEGER_KEY};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
}

pub type Result<T> = result::Result<T, Error>;

pub struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

pub struct RwTransaction<'a> {
    lmdb_txn: lmdb::RwTransaction<'a>,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Id(u64);

pub struct Node<'a> {
    pub id: Id,
    pub parent_id: Id,
    pub name: &'a str,
}

pub struct Entry<'a> {
    pub node: Node<'a>,
    pub objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction { lmdb_txn: txn }),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id(&self, txn: &mut RwTransaction) -> Result<Id> {
        let cursor = try!(txn.lmdb_txn
                             .open_rw_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.lmdb_txn
                .put(self.nodes,
                     &parent_id.as_bytes(),
                     &node.to_bytes(),
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.lmdb_txn
                .put(self.entries,
                     &id.as_bytes(),
                     &objectclass,
                     lmdb::WriteFlags::empty())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a>(&'a self, txn: &'a RwTransaction, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.lmdb_txn
                                  .get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node(&self, txn: &RwTransaction, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        // Perform a hierarchical path lookup
        // TODO: since LMDB is ordered, we could e.g. perform a binary search
        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            let parent_id = try!(parent_node).id;

            let mut cursor = try!(txn.lmdb_txn
                                     .open_ro_cursor(self.nodes)
                                     .map_err(|_err| Error::DbCorruptError));

            let mut child_node = None;

            for (id, node_bytes) in cursor.iter_from(parent_id.as_bytes()) {
                if id != parent_id.as_bytes() {
                    return Err(Error::NotFoundError);
                }

                let node = try!(Node::from_parent_id_and_bytes(parent_id, node_bytes));

                if node.name == *component {
                    child_node = Some(node);
                    break;
                }
            }

            child_node.ok_or(Error::NotFoundError)
        })
    }
}

impl<'a> RwTransaction<'a> {
    pub fn commit(self) -> Result<()> {
        self.lmdb_txn.commit().map_err(|_err| Error::TransactionError)
    }
}

#[test]
fn test_entry_lookup() {
    let path = Path::new("./tmp");
    let adapter = LmdbAdapter::create_database(path).unwrap();

    {
        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&mut txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        let hosts_id = domain_id.next();
        adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

        let host_id = hosts_id.next();
        adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host").unwrap();

        txn.commit().unwrap();
    }

    {
        let txn = adapter.rw_transaction().unwrap();

        {
            let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                               .unwrap();

            assert_eq!(entry.node.name, "master.example.com");
            assert_eq!(entry.objectclass, "host");
        }

        txn.commit().unwrap();
    }
}
<commit_msg>Transaction trait and RoTransaction<commit_after>extern crate lmdb;
extern crate lmdb_sys;

use std::{result, str};
use std::path::Path;
use lmdb::{Cursor, DUP_SORT, INTEGER_KEY};
use lmdb::Transaction as LmdbTransaction;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
}

pub type Result<T> = result::Result<T, Error>;

pub struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

pub struct RwTransaction<'a>(lmdb::RwTransaction<'a>);
pub struct RoTransaction<'a>(lmdb::RoTransaction<'a>);

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Id(u64);

pub struct Node<'a> {
    pub id: Id,
    pub parent_id: Id,
    pub name: &'a str,
}

pub struct Entry<'a> {
    pub node: Node<'a>,
    pub objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn ro_transaction(&self) -> Result<RoTransaction> {
        match self.env.begin_ro_txn() {
            Ok(txn) => Ok(RoTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id<T: Transaction>(&self, txn: &T) -> Result<Id> {
        let cursor = try!(txn.open_ro_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.put(self.nodes,
                     &parent_id.as_bytes(),
                     &node.to_bytes())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.put(self.entries,
                     &id.as_bytes(),
                     &objectclass.as_bytes())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a, T: Transaction>(&'a self, txn: &'a T, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node<T: Transaction>(&self, txn: &T, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        // Perform a hierarchical path lookup
        // TODO: since LMDB is ordered, we could e.g. perform a binary search
        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            let parent_id = try!(parent_node).id;

            let mut cursor = try!(txn.open_ro_cursor(self.nodes)
                                     .map_err(|_err| Error::DbCorruptError));

            let mut child_node = None;

            for (id, node_bytes) in cursor.iter_from(parent_id.as_bytes()) {
                if id != parent_id.as_bytes() {
                    return Err(Error::NotFoundError);
                }

                let node = try!(Node::from_parent_id_and_bytes(parent_id, node_bytes));

                if node.name == *component {
                    child_node = Some(node);
                    break;
                }
            }

            child_node.ok_or(Error::NotFoundError)
        })
    }
}

pub trait Transaction {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]>;
    fn commit(self) -> Result<()>;
    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor>;
}

impl<'a> Transaction for RwTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::TransactionError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> Transaction for RoTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::TransactionError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> RwTransaction<'a> {
    fn put(&mut self, database: lmdb::Database, key: &[u8], data: &[u8]) -> Result<()> {
        self.0.put(database, &key, &data, lmdb::WriteFlags::empty()).map_err(|_err| Error::TransactionError)
    }
}

#[test]
fn test_entry_lookup() {
    let path = Path::new("./tmp");
    let adapter = LmdbAdapter::create_database(path).unwrap();

    {
        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        let hosts_id = domain_id.next();
        adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

        let host_id = hosts_id.next();
        adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host").unwrap();

        txn.commit().unwrap();
    }

    {
        let txn = adapter.ro_transaction().unwrap();

        {
            let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                               .unwrap();

            assert_eq!(entry.node.name, "master.example.com");
            assert_eq!(entry.objectclass, "host");
        }

        txn.commit().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement};

mod expression;
mod types;

#[derive(PartialEq,Eq,Debug)]
pub enum LuaError {
    TypeError(String),
        IndexError(String),
        ArithmeticError(String),
}

type Result<T> = std::result::Result<T, LuaError>;

pub fn eval_file(input: &[u8]) {
    let ctx = types::LuaState::new();
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                match stmt {
                    Statement::LVarAssign(ass) => {
                        let values = ass.vals.expect("There should be some values. Why isn't there any value?!");
                        for (var, val) in ass.vars.iter().zip(values.iter()) {
                            let computed_value = expression::eval_expr(val, &ctx);
                            println!("Assigning {:?} to {:?}", computed_value, var);
                        }
                    }
                    Statement::Assignment(ass) => {
                        println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
                    }
                    _ => {}
                }
            }
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    }
}
<commit_msg>Split in two the eval_file function<commit_after>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement};

mod expression;
mod types;

#[derive(PartialEq,Eq,Debug)]
pub enum LuaError {
    TypeError(String),
    IndexError(String),
    ArithmeticError(String),
}

type Result<T> = std::result::Result<T, LuaError>;

pub fn parse_statement(stmt: &Statement, ctx: &mut types::LuaState) {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals.as_ref().expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                println!("Assigning {:?} to {:?}", computed_value, var);
            }
        }
        &Statement::Assignment(ref ass) => {
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
        }
        _ => {}
    }

}
pub fn eval_file(input: &[u8]) {
    let mut ctx = types::LuaState::new();
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                parse_statement(&stmt, &mut ctx)
            }
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    }
}
<|endoftext|>