<commit_before>use std::collections::{BTreeSet, VecDeque};

pub fn puzzle(input: &str) -> u32 {
    // let mut floor1 = BTreeSet::new();
    // floor1.insert(Component::Generator(Element::Thulium));
    // floor1.insert(Component::Microchip(Element::Thulium));
    // floor1.insert(Component::Generator(Element::Plutonium));
    // floor1.insert(Component::Generator(Element::Strontium));
    //
    // let mut floor2 = BTreeSet::new();
    // floor2.insert(Component::Microchip(Element::Plutonium));
    // floor2.insert(Component::Microchip(Element::Strontium));
    //
    // let mut floor3 = BTreeSet::new();
    // floor3.insert(Component::Generator(Element::Promethium));
    // floor3.insert(Component::Microchip(Element::Promethium));
    // floor3.insert(Component::Generator(Element::Ruthenium));
    // floor3.insert(Component::Microchip(Element::Ruthenium));

    let mut floor1 = BTreeSet::new();
    floor1.insert(Component::Microchip(Element::Hydrogen));
    floor1.insert(Component::Microchip(Element::Lithium));

    let mut floor2 = BTreeSet::new();
    floor2.insert(Component::Generator(Element::Hydrogen));

    let mut floor3 = BTreeSet::new();
    floor3.insert(Component::Generator(Element::Lithium));

    let initial_building_state = BuildingState {
        elevator_floor: 0,
        floors: [
            floor1,
            floor2,
            floor3,
            BTreeSet::new(),
        ],
    };
    let initial_world_state = WorldState {
        steps: 0,
        building: initial_building_state.clone()
    };
    let mut queue = VecDeque::new();
    queue.push_back(initial_world_state);
    let mut seen = BTreeSet::new();
    seen.insert(initial_building_state);
    let mut steps = 0;

    while let Some(world) = queue.pop_front() {
        if world.steps != steps {
            println!("{} step(s), queue: {}", world.steps, queue.len());
            steps = world.steps;
        }

        seen.insert(world.building.clone());

        if world.steps == 100 {
            panic!("too far!");
        }
        if world.in_end_state() {
            return world.steps;
        }

        for next_move in world.next_moves(&seen) {
            queue.push_back(next_move);
        }
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

#[derive(Debug)]
pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self, seen: &BTreeSet<BuildingState>) -> Vec<WorldState> {
        self.building.next_moves(seen).into_iter().map(|b| {
            WorldState {
                steps: self.steps + 1,
                building: b,
            }
        }).collect()
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Component {
    Microchip(Element),
    Generator(Element),
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Element {
    Hydrogen,
    Lithium,
    Thulium,
    Plutonium,
    Strontium,
    Promethium,
    Ruthenium,
}

#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct BuildingState {
    elevator_floor: usize,
    floors: [BTreeSet<Component>; 4],
}

impl Clone for BuildingState {
    fn clone(&self) -> BuildingState {
        BuildingState {
            elevator_floor: self.elevator_floor,
            floors: [
                self.floors[0].clone(),
                self.floors[1].clone(),
                self.floors[2].clone(),
                self.floors[3].clone(),
            ]
        }
    }
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }

    pub fn next_floors(&self) -> Vec<usize> {
        match self.elevator_floor {
            0 => vec![1],
            1 => vec![0, 2],
            2 => vec![1, 3],
            3 => vec![2],
            other => panic!("How did you get on floor {}, elevator?", other),
        }
    }

    pub fn elevator_combos(&self) -> BTreeSet<BTreeSet<Component>> {
        let mut result = BTreeSet::new();
        for &component0 in self.floors[self.elevator_floor].iter() {
            // Could take just this item on the elevator
            let mut set = BTreeSet::new();
            set.insert(component0);
            result.insert(set.clone());

            // Could take this item and one other, if they don't fry
            for &component1 in self.floors[self.elevator_floor].iter() {
                let mut scoped_set = set.clone();
                scoped_set.insert(component1);
                if !is_fried(&scoped_set) {
                    result.insert(scoped_set);
                }
            }
        }
        result
    }

    pub fn next_moves(&self, seen: &BTreeSet<BuildingState>)
                      -> Vec<BuildingState> {
        let mut valid_next_moves = vec![];
        for next_floor in self.next_floors() {
            for combo in self.elevator_combos() {
                let mut bs = (*self).clone();
                for &c in combo.iter() {
                    bs.floors[self.elevator_floor].remove(&c);
                    bs.floors[next_floor].insert(c);
                }
                bs.elevator_floor = next_floor;
                if !bs.has_fried_chips() && !seen.contains(&bs) {
                    valid_next_moves.push(bs);
                }
            }
        }
        valid_next_moves
    }

    pub fn has_fried_chips(&self) -> bool {
        self.floors.iter().any(is_fried)
    }
}

pub fn is_fried(components: &BTreeSet<Component>) -> bool {
    let mut generator_elements = BTreeSet::new();
    let mut microchip_elements = BTreeSet::new();

    for &component in components.iter() {
        match component {
            Component::Generator(el) => {
                generator_elements.insert(el);
            },
            Component::Microchip(el) => {
                microchip_elements.insert(el);
            },
        }
    }

    if generator_elements.is_empty() {
        return false;
    }

    microchip_elements.difference(&generator_elements).next().is_some()
}

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

    #[test]
    fn not_in_end_state() {
        let mut floor1 = BTreeSet::new();
        floor1.insert(Component::Microchip(Element::Hydrogen));
        floor1.insert(Component::Microchip(Element::Lithium));

        let mut floor2 = BTreeSet::new();
        floor2.insert(Component::Generator(Element::Hydrogen));

        let mut floor3 = BTreeSet::new();
        floor3.insert(Component::Generator(Element::Lithium));

        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    floor1,
                    floor2,
                    floor3,
                    BTreeSet::new(),
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let mut floor4 = BTreeSet::new();
        floor4.insert(Component::Generator(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Lithium));
        floor4.insert(Component::Generator(Element::Lithium));
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    BTreeSet::new(),
                    BTreeSet::new(),
                    BTreeSet::new(),
                    floor4,
                ],
            }
        };

        assert!(world_state.in_end_state());
    }

    #[test]
    fn two_microchips_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_alone_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn two_generators_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_and_matching_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_attached_to_matching_generator_not_fried_by_other_generator() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_without_its_generator_with_another_generator_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!(is_fried(&hs));
    }

    #[test]
    fn generator_with_a_microchip_without_its_generator_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!(is_fried(&hs));
    }

    #[test]
    fn generator_with_a_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn generator_with_its_microchip_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn generator_with_a_microchip_with_its_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }
}
<commit_msg>I don't actually care about Ord/set of sets for the seen set<commit_after>use std::collections::{BTreeSet, VecDeque, HashSet};

pub fn puzzle(input: &str) -> u32 {
    // let mut floor1 = BTreeSet::new();
    // floor1.insert(Component::Generator(Element::Thulium));
    // floor1.insert(Component::Microchip(Element::Thulium));
    // floor1.insert(Component::Generator(Element::Plutonium));
    // floor1.insert(Component::Generator(Element::Strontium));
    //
    // let mut floor2 = BTreeSet::new();
    // floor2.insert(Component::Microchip(Element::Plutonium));
    // floor2.insert(Component::Microchip(Element::Strontium));
    //
    // let mut floor3 = BTreeSet::new();
    // floor3.insert(Component::Generator(Element::Promethium));
    // floor3.insert(Component::Microchip(Element::Promethium));
    // floor3.insert(Component::Generator(Element::Ruthenium));
    // floor3.insert(Component::Microchip(Element::Ruthenium));

    let mut floor1 = BTreeSet::new();
    floor1.insert(Component::Microchip(Element::Hydrogen));
    floor1.insert(Component::Microchip(Element::Lithium));

    let mut floor2 = BTreeSet::new();
    floor2.insert(Component::Generator(Element::Hydrogen));

    let mut floor3 = BTreeSet::new();
    floor3.insert(Component::Generator(Element::Lithium));

    let initial_building_state = BuildingState {
        elevator_floor: 0,
        floors: [
            floor1,
            floor2,
            floor3,
            BTreeSet::new(),
        ],
    };
    let initial_world_state = WorldState {
        steps: 0,
        building: initial_building_state.clone()
    };
    let mut queue = VecDeque::new();
    queue.push_back(initial_world_state);
    let mut seen = HashSet::new();
    seen.insert(initial_building_state);
    let mut steps = 0;

    while let Some(world) = queue.pop_front() {
        if world.steps != steps {
            println!("{} step(s), queue: {}", world.steps, queue.len());
            steps = world.steps;
        }

        seen.insert(world.building.clone());

        if world.steps == 100 {
            panic!("too far!");
        }
        if world.in_end_state() {
            return world.steps;
        }

        for next_move in world.next_moves(&seen) {
            queue.push_back(next_move);
        }
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

#[derive(Debug)]
pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>) -> Vec<WorldState> {
        self.building.next_moves(seen).into_iter().map(|b| {
            WorldState {
                steps: self.steps + 1,
                building: b,
            }
        }).collect()
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Component {
    Microchip(Element),
    Generator(Element),
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Element {
    Hydrogen,
    Lithium,
    Thulium,
    Plutonium,
    Strontium,
    Promethium,
    Ruthenium,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct BuildingState {
    elevator_floor: usize,
    floors: [BTreeSet<Component>; 4],
}

impl Clone for BuildingState {
    fn clone(&self) -> BuildingState {
        BuildingState {
            elevator_floor: self.elevator_floor,
            floors: [
                self.floors[0].clone(),
                self.floors[1].clone(),
                self.floors[2].clone(),
                self.floors[3].clone(),
            ]
        }
    }
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }

    pub fn next_floors(&self) -> Vec<usize> {
        match self.elevator_floor {
            0 => vec![1],
            1 => vec![0, 2],
            2 => vec![1, 3],
            3 => vec![2],
            other => panic!("How did you get on floor {}, elevator?", other),
        }
    }

    pub fn elevator_combos(&self) -> BTreeSet<BTreeSet<Component>> {
        let mut result = BTreeSet::new();
        for &component0 in self.floors[self.elevator_floor].iter() {
            // Could take just this item on the elevator
            let mut set = BTreeSet::new();
            set.insert(component0);
            result.insert(set.clone());

            // Could take this item and one other, if they don't fry
            for &component1 in self.floors[self.elevator_floor].iter() {
                let mut scoped_set = set.clone();
                scoped_set.insert(component1);
                if !is_fried(&scoped_set) {
                    result.insert(scoped_set);
                }
            }
        }
        result
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>)
                      -> Vec<BuildingState> {
        let mut valid_next_moves = vec![];
        for next_floor in self.next_floors() {
            for combo in self.elevator_combos() {
                let mut bs = (*self).clone();
                for &c in combo.iter() {
                    bs.floors[self.elevator_floor].remove(&c);
                    bs.floors[next_floor].insert(c);
                }
                bs.elevator_floor = next_floor;
                if !bs.has_fried_chips() && !seen.contains(&bs) {
                    valid_next_moves.push(bs);
                }
            }
        }
        valid_next_moves
    }

    pub fn has_fried_chips(&self) -> bool {
        self.floors.iter().any(is_fried)
    }
}

pub fn is_fried(components: &BTreeSet<Component>) -> bool {
    let mut generator_elements = BTreeSet::new();
    let mut microchip_elements = BTreeSet::new();

    for &component in components.iter() {
        match component {
            Component::Generator(el) => {
                generator_elements.insert(el);
            },
            Component::Microchip(el) => {
                microchip_elements.insert(el);
            },
        }
    }

    if generator_elements.is_empty() {
        return false;
    }

    microchip_elements.difference(&generator_elements).next().is_some()
}

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

    #[test]
    fn not_in_end_state() {
        let mut floor1 = BTreeSet::new();
        floor1.insert(Component::Microchip(Element::Hydrogen));
        floor1.insert(Component::Microchip(Element::Lithium));

        let mut floor2 = BTreeSet::new();
        floor2.insert(Component::Generator(Element::Hydrogen));

        let mut floor3 = BTreeSet::new();
        floor3.insert(Component::Generator(Element::Lithium));

        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    floor1,
                    floor2,
                    floor3,
                    BTreeSet::new(),
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let mut floor4 = BTreeSet::new();
        floor4.insert(Component::Generator(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Lithium));
        floor4.insert(Component::Generator(Element::Lithium));
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    BTreeSet::new(),
                    BTreeSet::new(),
                    BTreeSet::new(),
                    floor4,
                ],
            }
        };

        assert!(world_state.in_end_state());
    }

    #[test]
    fn two_microchips_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_alone_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn two_generators_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_and_matching_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_attached_to_matching_generator_not_fried_by_other_generator() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn microchip_without_its_generator_with_another_generator_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Hydrogen));
        assert!(is_fried(&hs));
    }

    #[test]
    fn generator_with_a_microchip_without_its_generator_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!(is_fried(&hs));
    }

    #[test]
    fn generator_with_a_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn generator_with_its_microchip_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }

    #[test]
    fn generator_with_a_microchip_with_its_generator_not_fried() {
        let mut hs = BTreeSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));
        assert!( ! is_fried(&hs) );
    }
}
<|endoftext|>


<commit_before>mod os;

#[cfg(all(unix, not(target_os = "macos")))]
pub use os::unix::*;
#[cfg(target_os = "macos")]
pub use os::macos::*;
#[cfg(windows)]
pub use os::windows::*;

#[derive(Debug)]
pub enum Error {
    Ffi(std::ffi::NulError),
    Io(std::io::Error),
    S(String),
}

impl From<std::ffi::NulError> for Error {
    fn from(err: std::ffi::NulError) -> Error {
        Error::Ffi(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::S(err)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::Path;

    #[test]
    fn integration_basic() {
        let sample = Path::new("./Cargo.toml").canonicalize().unwrap();
        let result = find_mountpoint_pre_canonicalized(sample.as_path());
        assert_eq!(result.unwrap().to_str().unwrap(), "/");
    }

    #[test]
    fn integration_basic_without_canonicalization() {
        let sample = Path::new("./Cargo.toml");
        let result = find_mountpoint(sample);
        assert_eq!(result.unwrap().to_str().unwrap(), "/");
    }

    // only run this if you have a Boot Camp volume named energeia on your system.
    #[test]
    #[ignore]
    fn integration_another_fs() {
        let sample = Path::new("/Volumes/energeia/CONFIG.SYS");
        let result = find_mountpoint_pre_canonicalized(sample);
        assert_eq!(result.unwrap().to_str().unwrap(), "/Volumes/energeia");
    }

    #[test]
    #[should_panic(expected = "No such file or directory")]
    fn nonexistent_path() {
        let sample = Path::new("/Volumes/NOxSUCHxMOUNT/prj/Cargo.toml");
        find_mountpoint_pre_canonicalized(sample).unwrap();
    }

    #[test]
    #[should_panic(expected = "No such file or directory")]
    fn nonexistent_path_without_canonicalization() {
        let sample = Path::new("../vegan/porkchop/sandwiches");
        find_mountpoint(sample).unwrap();
    }
}
<commit_msg>make AppVeyor happy<commit_after>mod os;

#[cfg(all(unix, not(target_os = "macos")))]
pub use os::unix::*;
#[cfg(target_os = "macos")]
pub use os::macos::*;
#[cfg(windows)]
pub use os::windows::*;

#[derive(Debug)]
pub enum Error {
    Ffi(std::ffi::NulError),
    Io(std::io::Error),
    S(String),
}

impl From<std::ffi::NulError> for Error {
    fn from(err: std::ffi::NulError) -> Error {
        Error::Ffi(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::S(err)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::Path;

    #[test]
    fn integration_basic() {
        let sample = Path::new("./Cargo.toml").canonicalize().unwrap();
        let result = find_mountpoint_pre_canonicalized(sample.as_path());
        #[cfg(unix)]
        assert_eq!(result.unwrap().to_str().unwrap(), "/");
        #[cfg(windows)]
        assert_eq!(result.unwrap().to_str().unwrap(), "\\\\?\\C:");
    }

    #[test]
    fn integration_basic_without_canonicalization() {
        let sample = Path::new("./Cargo.toml");
        let result = find_mountpoint(sample);
        #[cfg(unix)]
        assert_eq!(result.unwrap().to_str().unwrap(), "/");
        #[cfg(windows)]
        assert_eq!(result.unwrap().to_str().unwrap(), "\\\\?\\C:");
    }

    // only run this if you have a Boot Camp volume named energeia on your system.
    #[test]
    #[ignore]
    fn integration_another_fs() {
        let sample = Path::new("/Volumes/energeia/CONFIG.SYS");
        let result = find_mountpoint_pre_canonicalized(sample);
        assert_eq!(result.unwrap().to_str().unwrap(), "/Volumes/energeia");
    }

    #[test]
    #[should_panic]
    fn nonexistent_path() {
        let sample = Path::new("/Volumes/NOxSUCHxMOUNT/prj/Cargo.toml");
        find_mountpoint_pre_canonicalized(sample).unwrap();
    }

    #[test]
    #[should_panic]
    fn nonexistent_path_without_canonicalization() {
        let sample = Path::new("../vegan/porkchop/sandwiches");
        find_mountpoint(sample).unwrap();
    }
}
<|endoftext|>


<commit_before>//! A pure-Rust LDAP client library using the Tokio stack.
//!
//! ## Usage
//!
//! In `Cargo.toml`:
//!
//! ```toml
//! [dependencies.ldap3]
//! version = "0.7"
//! ```
//!
//! ## Summary
//!
//! The library provides both synchronous and asynchronous interfaces. The [`LdapConn`](struct.LdapConn.html)
//! structure is the starting point for all synchronous operations. [`LdapConnAsync`](struct.LdapConnAsync.html)
//! is its asynchronous analogue, and [`Ldap`](struct.Ldap.html) is the low-level asynchronous handle used
//! internally by `LdapConn`, and explicitly by the users of the asynchronous interface.
//!
//! In the [struct list](#structs), async-related structs have an asterisk (__*__) after
//! the short description.
//!
//! The documentation is written for readers familiar with LDAP concepts and terminology,
//! which it won't attempt to explain.
//!
//! ## Compile-time features
//!
//! The following features are available at compile time:
//!
//! * __sync__ (enabled by default): Synchronous API support.
//!
//! * __tls__ (enabled by default): TLS support, backed by the `native-tls` crate, which uses
//!  a platform-specific TLS backend. This is an alias for __tls-native__.
//!
//! * __tls-rustls__ (disabled by default): TLS support, backed by the Rustls library.
//!
//! Without any features, only plain TCP connections (and Unix domain sockets on Unix-like
//! platforms) are available. For TLS support, __tls__ and __tls-rustls__ are mutually
//! exclusive: choosing both will produce a compile-time error.
//!
//! ## Examples
//!
//! The following two examples perform exactly the same operation and should produce identical
//! results. They should be run against the example server in the `data` subdirectory of the crate source.
//! Other sample programs expecting the same server setup can be found in the `examples` subdirectory.
//!
//! ### Synchronous search
//!
//! ```rust,no_run
//! use ldap3::{LdapConn, Scope, SearchEntry};
//! use ldap3::result::Result;
//!
//! fn main() -> Result<()> {
//!     let mut ldap = LdapConn::new("ldap://localhost:2389")?;
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     )?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(ldap.unbind()?)
//! }
//! ```
//!
//! ### Asynchronous search
//!
//! ```rust,no_run
//! use ldap3::{LdapConnAsync, Scope, SearchEntry};
//! use ldap3::result::Result;
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//!     let (conn, mut ldap) = LdapConnAsync::new("ldap://localhost:2389").await?;
//!     ldap3::drive!(conn);
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     ).await?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(ldap.unbind().await?)
//! }
//! ```

#[macro_use]
extern crate nom;
#[macro_use]
pub extern crate log;

/// Type alias for the LDAP message ID.
pub type RequestId = i32;

pub mod adapters;
pub mod asn1 {
    //! ASN.1 structure construction and parsing.
    //!
    //! This section is deliberately under-documented; it's expected that the ASN.1 subsystem will
    //! be extensively overhauled in the future. If you need examples of using the present interface
    //! for, e.g., implementing a new extended operation or a control, consult the source of existing
    //! exops/controls.
    pub use lber::common::TagClass;
    pub use lber::parse::{parse_tag, parse_uint};
    pub use lber::structure::{StructureTag, PL};
    pub use lber::structures::{
        ASNTag, Boolean, Enumerated, ExplicitTag, Integer, Null, OctetString, Sequence, Set, Tag,
    };
    pub use lber::universal::Types;
    pub use lber::write;
    pub use lber::IResult;
}
mod conn;
pub mod controls {
    //! Control construction and parsing.
    //!
    //! A control can be associated with a request or a response. Several common
    //! controls, such as [`PagedResults`](struct.PagedResults.html), are implemented
    //! directly by this library. If an implemented control has the same form for
    //! the request and the response, there will be a single structure for both.
    //! (This is the case for `PagedResults`.) If the response control is different,
    //! its name will consist of the request control name with the `Resp` suffix.
    //!
    //! A request control can be created by instantiating its structure and converting
    //! it to ASN.1 with `into()` when passing the instance or constructing the request
    //! control vector in the call to [`with_controls()`](../struct.LdapConn.html#method.with_controls).
    //! A third-party control must implement the conversion from an instance
    //! of itself to [`RawControl`](struct.RawControl.html), a general form of control.
    //!
    //! `RawControl`, together with an optional instance of [`ControlType`](enum.ControlType.html),
    //! forms the type [`Control`](struct.Control.html); a vector of `Control`s is part
    //! of the result of all LDAP operation which return one.
    //!
    //! The first element of `Control` will have a value if the parser recognizes
    //! the control's OID as one that is implemented by the library itself. Since the
    //! list of implemented controls is expected to grow, the `ControlType` enum cannot
    //! be exhaustively matched.
    //!
    //! A recognized response control can be parsed by calling
    //! [`parse()`](struct.RawControl.html#method.parse) on the instance of `RawControl`
    //! representing it. A third-party control must implement the
    //! [`ControlParser`](trait.ControlParser.html) trait to support this interface.
    //!
    //! ### Example
    //!
    //! With an `LdapResult` in `res`, iterating through controls and matching the desired ones
    //! could be done like this:
    //!
    //! ```rust,no_run
    //! # use ldap3::controls::{Control, ControlType, PagedResults};
    //! # use ldap3::result::Result;
    //! # use ldap3::LdapConn;
    //! # fn main() -> Result<()> {
    //! # let mut ldap = LdapConn::new("ldap://localhost")?;
    //! # let res = ldap.simple_bind("", "")?.success()?;
    //! for ctrl in res.ctrls {
    //!     match ctrl {
    //!         // matching a control implemented by the library
    //!         Control(Some(ControlType::PagedResults), ref raw) => {
    //!             dbg!(raw.parse::<PagedResults>());
    //!         },
    //!         // matching a control unknown to the library
    //!         // the OID is actually that of PagedResults
    //!         Control(None, ref raw) if raw.ctype == "1.2.840.113556.1.4.319" => {
    //!             dbg!(raw.parse::<PagedResults>());
    //!         },
    //!         _ => (),
    //!     }
    //! }
    //! # Ok(())
    //! # }
    pub use crate::controls_impl::parse_syncinfo;
    pub use crate::controls_impl::{Assertion, ManageDsaIt, PagedResults, ProxyAuth, RelaxRules};
    pub use crate::controls_impl::{
        Control, ControlParser, ControlType, CriticalControl, MakeCritical, RawControl,
    };
    pub use crate::controls_impl::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};
    pub use crate::controls_impl::{EntryState, RefreshMode, SyncDone, SyncInfo, SyncRequest, SyncState};
}
mod controls_impl;
mod exop_impl;
pub mod exop {
    //! Extended operation construction and parsing.
    //!
    //! A generic exop is represented by [`Exop`](struct.Exop.html). If a particular
    //! exop is implemented by this library, it may have one or two associated structs;
    //! one for constructing requests, and another for parsing responses. If request and
    //! response are the same, there is only the request struct; if they are different,
    //! the response struct's name will consist of the request struct name with the
    //! `Resp` suffix.
    //!
    //! A request struct must implement the `From` conversion of itself into `Exop`.
    //! A response struct must implement the [`ExopParser`](trait.ExopParser.html)
    //! trait.
    pub use crate::exop_impl::{Exop, ExopParser, WhoAmI, WhoAmIResp};
}
mod filter;
mod ldap;
mod protocol;
pub mod result;
mod search;
#[cfg(feature = "sync")]
mod sync;
mod util;

pub use conn::{LdapConnAsync, LdapConnSettings};
pub use filter::parse as parse_filter;
pub use ldap::{Ldap, Mod};
pub use result::{LdapError, LdapResult, SearchResult};
pub use search::parse_refs;
pub use search::{
    DerefAliases, ResultEntry, Scope, SearchEntry, SearchOptions, SearchStream, StreamState,
};
#[cfg(feature = "sync")]
pub use sync::{EntryStream, LdapConn};
pub use util::{dn_escape, ldap_escape};
<commit_msg>Cargo fmt<commit_after>//! A pure-Rust LDAP client library using the Tokio stack.
//!
//! ## Usage
//!
//! In `Cargo.toml`:
//!
//! ```toml
//! [dependencies.ldap3]
//! version = "0.7"
//! ```
//!
//! ## Summary
//!
//! The library provides both synchronous and asynchronous interfaces. The [`LdapConn`](struct.LdapConn.html)
//! structure is the starting point for all synchronous operations. [`LdapConnAsync`](struct.LdapConnAsync.html)
//! is its asynchronous analogue, and [`Ldap`](struct.Ldap.html) is the low-level asynchronous handle used
//! internally by `LdapConn`, and explicitly by the users of the asynchronous interface.
//!
//! In the [struct list](#structs), async-related structs have an asterisk (__*__) after
//! the short description.
//!
//! The documentation is written for readers familiar with LDAP concepts and terminology,
//! which it won't attempt to explain.
//!
//! ## Compile-time features
//!
//! The following features are available at compile time:
//!
//! * __sync__ (enabled by default): Synchronous API support.
//!
//! * __tls__ (enabled by default): TLS support, backed by the `native-tls` crate, which uses
//!  a platform-specific TLS backend. This is an alias for __tls-native__.
//!
//! * __tls-rustls__ (disabled by default): TLS support, backed by the Rustls library.
//!
//! Without any features, only plain TCP connections (and Unix domain sockets on Unix-like
//! platforms) are available. For TLS support, __tls__ and __tls-rustls__ are mutually
//! exclusive: choosing both will produce a compile-time error.
//!
//! ## Examples
//!
//! The following two examples perform exactly the same operation and should produce identical
//! results. They should be run against the example server in the `data` subdirectory of the crate source.
//! Other sample programs expecting the same server setup can be found in the `examples` subdirectory.
//!
//! ### Synchronous search
//!
//! ```rust,no_run
//! use ldap3::{LdapConn, Scope, SearchEntry};
//! use ldap3::result::Result;
//!
//! fn main() -> Result<()> {
//!     let mut ldap = LdapConn::new("ldap://localhost:2389")?;
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     )?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(ldap.unbind()?)
//! }
//! ```
//!
//! ### Asynchronous search
//!
//! ```rust,no_run
//! use ldap3::{LdapConnAsync, Scope, SearchEntry};
//! use ldap3::result::Result;
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//!     let (conn, mut ldap) = LdapConnAsync::new("ldap://localhost:2389").await?;
//!     ldap3::drive!(conn);
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     ).await?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(ldap.unbind().await?)
//! }
//! ```

#[macro_use]
extern crate nom;
#[macro_use]
pub extern crate log;

/// Type alias for the LDAP message ID.
pub type RequestId = i32;

pub mod adapters;
pub mod asn1 {
    //! ASN.1 structure construction and parsing.
    //!
    //! This section is deliberately under-documented; it's expected that the ASN.1 subsystem will
    //! be extensively overhauled in the future. If you need examples of using the present interface
    //! for, e.g., implementing a new extended operation or a control, consult the source of existing
    //! exops/controls.
    pub use lber::common::TagClass;
    pub use lber::parse::{parse_tag, parse_uint};
    pub use lber::structure::{StructureTag, PL};
    pub use lber::structures::{
        ASNTag, Boolean, Enumerated, ExplicitTag, Integer, Null, OctetString, Sequence, Set, Tag,
    };
    pub use lber::universal::Types;
    pub use lber::write;
    pub use lber::IResult;
}
mod conn;
pub mod controls {
    //! Control construction and parsing.
    //!
    //! A control can be associated with a request or a response. Several common
    //! controls, such as [`PagedResults`](struct.PagedResults.html), are implemented
    //! directly by this library. If an implemented control has the same form for
    //! the request and the response, there will be a single structure for both.
    //! (This is the case for `PagedResults`.) If the response control is different,
    //! its name will consist of the request control name with the `Resp` suffix.
    //!
    //! A request control can be created by instantiating its structure and converting
    //! it to ASN.1 with `into()` when passing the instance or constructing the request
    //! control vector in the call to [`with_controls()`](../struct.LdapConn.html#method.with_controls).
    //! A third-party control must implement the conversion from an instance
    //! of itself to [`RawControl`](struct.RawControl.html), a general form of control.
    //!
    //! `RawControl`, together with an optional instance of [`ControlType`](enum.ControlType.html),
    //! forms the type [`Control`](struct.Control.html); a vector of `Control`s is part
    //! of the result of all LDAP operation which return one.
    //!
    //! The first element of `Control` will have a value if the parser recognizes
    //! the control's OID as one that is implemented by the library itself. Since the
    //! list of implemented controls is expected to grow, the `ControlType` enum cannot
    //! be exhaustively matched.
    //!
    //! A recognized response control can be parsed by calling
    //! [`parse()`](struct.RawControl.html#method.parse) on the instance of `RawControl`
    //! representing it. A third-party control must implement the
    //! [`ControlParser`](trait.ControlParser.html) trait to support this interface.
    //!
    //! ### Example
    //!
    //! With an `LdapResult` in `res`, iterating through controls and matching the desired ones
    //! could be done like this:
    //!
    //! ```rust,no_run
    //! # use ldap3::controls::{Control, ControlType, PagedResults};
    //! # use ldap3::result::Result;
    //! # use ldap3::LdapConn;
    //! # fn main() -> Result<()> {
    //! # let mut ldap = LdapConn::new("ldap://localhost")?;
    //! # let res = ldap.simple_bind("", "")?.success()?;
    //! for ctrl in res.ctrls {
    //!     match ctrl {
    //!         // matching a control implemented by the library
    //!         Control(Some(ControlType::PagedResults), ref raw) => {
    //!             dbg!(raw.parse::<PagedResults>());
    //!         },
    //!         // matching a control unknown to the library
    //!         // the OID is actually that of PagedResults
    //!         Control(None, ref raw) if raw.ctype == "1.2.840.113556.1.4.319" => {
    //!             dbg!(raw.parse::<PagedResults>());
    //!         },
    //!         _ => (),
    //!     }
    //! }
    //! # Ok(())
    //! # }
    pub use crate::controls_impl::parse_syncinfo;
    pub use crate::controls_impl::{Assertion, ManageDsaIt, PagedResults, ProxyAuth, RelaxRules};
    pub use crate::controls_impl::{
        Control, ControlParser, ControlType, CriticalControl, MakeCritical, RawControl,
    };
    pub use crate::controls_impl::{
        EntryState, RefreshMode, SyncDone, SyncInfo, SyncRequest, SyncState,
    };
    pub use crate::controls_impl::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};
}
mod controls_impl;
mod exop_impl;
pub mod exop {
    //! Extended operation construction and parsing.
    //!
    //! A generic exop is represented by [`Exop`](struct.Exop.html). If a particular
    //! exop is implemented by this library, it may have one or two associated structs;
    //! one for constructing requests, and another for parsing responses. If request and
    //! response are the same, there is only the request struct; if they are different,
    //! the response struct's name will consist of the request struct name with the
    //! `Resp` suffix.
    //!
    //! A request struct must implement the `From` conversion of itself into `Exop`.
    //! A response struct must implement the [`ExopParser`](trait.ExopParser.html)
    //! trait.
    pub use crate::exop_impl::{Exop, ExopParser, WhoAmI, WhoAmIResp};
}
mod filter;
mod ldap;
mod protocol;
pub mod result;
mod search;
#[cfg(feature = "sync")]
mod sync;
mod util;

pub use conn::{LdapConnAsync, LdapConnSettings};
pub use filter::parse as parse_filter;
pub use ldap::{Ldap, Mod};
pub use result::{LdapError, LdapResult, SearchResult};
pub use search::parse_refs;
pub use search::{
    DerefAliases, ResultEntry, Scope, SearchEntry, SearchOptions, SearchStream, StreamState,
};
#[cfg(feature = "sync")]
pub use sync::{EntryStream, LdapConn};
pub use util::{dn_escape, ldap_escape};
<|endoftext|>


<commit_before>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate clang;
#[macro_use]
extern crate failure;
extern crate glob;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate python_parser;
extern crate regex;
extern crate run_script;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate slog_envlogger;
extern crate snapshot;
extern crate walkdir;
extern crate yaml_rust;

pub mod analysis;
pub mod entity;
pub mod language_type;
pub mod project_parameters;
pub mod stubs;
pub mod synthesis;
pub mod value_parser;

use analysis::{Analysis, ProjectFile};
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use project_parameters::ProjectParameters;
use std::path::PathBuf;
use synthesis::*;

static DEFAULT_ENV_YML: &str = include_str!("../stubs/environment/env_stubs.yml");

#[derive(Default, Debug)]
/// Global structure representing the Thinline lib.
pub struct Thinline<T>
where
    T: LanguageType,
{
    /// The parsed project parameters.
    pub project_parameters: ProjectParameters,

    /// The structure holding the analysis_c data.
    pub analysis: Analysis<T>,

    /// The structure holding the synthesized testdata.
    pub synthesis: Synthesis<T>,
}

impl<T> Thinline<T>
where
    T: LanguageType,
{
    /// Creates an instance of the lib containing Thinlines functionality.
    pub fn new() -> Self {
        Self::default()
    }

    /// Starts the analysis of the target project.
    pub fn analyze<P: Into<PathBuf>>(
        &mut self,
        source_dir: P,
        thinline_cfg: &str,
        build: bool,
    ) -> Fallible<()> {
        let source_dir_path = source_dir.into();

        // Parses the project config
        self.parse_project_config(&source_dir_path, thinline_cfg)?;

        // Analyze the project at the given source directory
        self.analyze_project(&source_dir_path)?;

        // Builds target project when build flag is set
        if build {
            self.project_parameters.build_script.run(&source_dir_path)?;
        }

        Ok(())
    }

    /// Parses configuration from the given config yaml.
    fn parse_project_config<P: Into<PathBuf>>(
        &mut self,
        project_dir: P,
        config_name: &str,
    ) -> Fallible<()> {
        let project_config = project_dir.into().join(config_name);

        if !project_config.exists() || !project_config.is_file() {
            return Err(format_err!(
                "The given project config file '{}' does not exist or is a directory.",
                project_config
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project config file."))?
            ));
        }

        self.project_parameters = ProjectParameters::parse(
            project_config
                .to_str()
                .ok_or_else(|| err_msg("Unable to stringify project config file."))?,
        )?;

        debug!("{:#?}", self.project_parameters);

        Ok(())
    }

    /// Analyzes the project which should be tested.
    fn analyze_project<P: Into<PathBuf>>(&self, project_path: P) -> Fallible<()> {
        let project_path_p = project_path.into();

        if let Some(project_path_s) = project_path_p.to_str() {
            info!("Starting project analysis at '{}'", project_path_s);
        }

        if project_path_p.is_dir() {
            // Project path is a directory, thus it is neccessay to traverse to the project
            // and collect all the sources.
            self.analysis
                .collect_sources(&project_path_p, &self.project_parameters.source_dirs)?;
        }

        if project_path_p.is_file() {
            if let Some(ext) = project_path_p.extension() {
                // Project path is a file and has the right extension.
                if T::file_types().contains(
                    &ext.to_str()
                        .ok_or_else(|| err_msg("Unable to stringify file extension."))?,
                ) {
                    // Push it to the project file vectory for analyzing purposes.
                    self.analysis
                        .project_files_mut()
                        .push(ProjectFile::new(&project_path_p));
                }
            }
        }

        self.analysis.extract_entities()?;

        Ok(())
    }

    pub fn synthesize_tests(&mut self) -> Fallible<()> {
        self.synthesis = Synthesis::new();

        self.synthesis.parse_stubs(DEFAULT_ENV_YML)?;

        Ok(())
    }
}
<commit_msg>Make thinlinelib members private<commit_after>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate clang;
#[macro_use]
extern crate failure;
extern crate glob;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate python_parser;
extern crate regex;
extern crate run_script;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate slog_envlogger;
extern crate snapshot;
extern crate walkdir;
extern crate yaml_rust;

pub mod analysis;
pub mod entity;
pub mod language_type;
pub mod project_parameters;
pub mod stubs;
pub mod synthesis;
pub mod value_parser;

use analysis::{Analysis, ProjectFile};
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use project_parameters::ProjectParameters;
use std::path::PathBuf;
use synthesis::*;

static DEFAULT_ENV_YML: &str = include_str!("../stubs/environment/env_stubs.yml");

#[derive(Default, Debug)]
/// Global structure representing the Thinline lib.
pub struct Thinline<T>
where
    T: LanguageType,
{
    /// The parsed project parameters.
    project_parameters: ProjectParameters,

    /// The structure holding the analysis_c data.
    analysis: Analysis<T>,

    /// The structure holding the synthesized testdata.
    synthesis: Synthesis<T>,
}

impl<T> Thinline<T>
where
    T: LanguageType,
{
    /// Creates an instance of the lib containing Thinlines functionality.
    pub fn new() -> Self {
        Self::default()
    }

    /// Starts the analysis of the target project.
    pub fn analyze<P: Into<PathBuf>>(
        &mut self,
        source_dir: P,
        thinline_cfg: &str,
        build: bool,
    ) -> Fallible<()> {
        let source_dir_path = source_dir.into();

        // Parses the project config
        self.parse_project_config(&source_dir_path, thinline_cfg)?;

        // Analyze the project at the given source directory
        self.analyze_project(&source_dir_path)?;

        // Builds target project when build flag is set
        if build {
            self.project_parameters.build_script.run(&source_dir_path)?;
        }

        Ok(())
    }

    /// Parses configuration from the given config yaml.
    fn parse_project_config<P: Into<PathBuf>>(
        &mut self,
        project_dir: P,
        config_name: &str,
    ) -> Fallible<()> {
        let project_config = project_dir.into().join(config_name);

        if !project_config.exists() || !project_config.is_file() {
            return Err(format_err!(
                "The given project config file '{}' does not exist or is a directory.",
                project_config
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project config file."))?
            ));
        }

        self.project_parameters = ProjectParameters::parse(
            project_config
                .to_str()
                .ok_or_else(|| err_msg("Unable to stringify project config file."))?,
        )?;

        debug!("{:#?}", self.project_parameters);

        Ok(())
    }

    /// Analyzes the project which should be tested.
    fn analyze_project<P: Into<PathBuf>>(&self, project_path: P) -> Fallible<()> {
        let project_path_p = project_path.into();

        if let Some(project_path_s) = project_path_p.to_str() {
            info!("Starting project analysis at '{}'", project_path_s);
        }

        if project_path_p.is_dir() {
            // Project path is a directory, thus it is neccessay to traverse to the project
            // and collect all the sources.
            self.analysis
                .collect_sources(&project_path_p, &self.project_parameters.source_dirs)?;
        }

        if project_path_p.is_file() {
            if let Some(ext) = project_path_p.extension() {
                // Project path is a file and has the right extension.
                if T::file_types().contains(
                    &ext.to_str()
                        .ok_or_else(|| err_msg("Unable to stringify file extension."))?,
                ) {
                    // Push it to the project file vectory for analyzing purposes.
                    self.analysis
                        .project_files_mut()
                        .push(ProjectFile::new(&project_path_p));
                }
            }
        }

        self.analysis.extract_entities()?;

        Ok(())
    }

    pub fn synthesize(&mut self) -> Fallible<()> {
        self.synthesis.parse_stubs(DEFAULT_ENV_YML)?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Mul<f32, Output = T> + Add<Output = T> + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i - 1] <= t < knot[i]
        let i = match upper_bounds(&self.knots[self.degree - 1..self.knots.len() - self.degree], t) {
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boors(t, self.degree, i)
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is terrible,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            self.control_points[i]
        } else {
            println!("Looking at k = {}, i = {}", k, i);
            let denom = self.knots[i + self.degree - k] - self.knots[i - 1];
            let a = (self.knots[i + self.degree - k] - t) / denom;
            let b = (t - self.knots[i - 1]) / denom;
            self.de_boors(t, k - 1, i - 1) * a + self.de_boors(t, k - 1, i) * b
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};
    use std::iter;

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    #[derive(Copy, Clone, Debug)]
    struct Pointi {
        x: i32,
        y: i32,
    }
    impl Pointi {
        fn new(x: i32, y: i32) -> Pointi {
            Pointi { x: x, y: y }
        }
    }
    impl Mul<f32> for Pointi {
        type Output = Pointi;
        fn mul(self, rhs: f32) -> Pointi {
            Pointi { x: (self.x as f32 * rhs) as i32,
                    y: (self.y as f32 * rhs) as i32 }
        }
    }
    impl Add for Pointi {
        type Output = Pointi;
        fn add(self, rhs: Pointi) -> Pointi {
            Pointi { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    #[test]
    fn linear_bspline(){
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 1.0, 2.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }

    #[test]
    fn bspline_plot(){
        let points = vec![Pointi::new(10, 10), Pointi::new(20, 20), Pointi::new(10, 20)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(2, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);

        // TODO: This doesn't compute or plot the correct curve
        let plot_w = 40;
        let plot_h = 40;
        let mut plot: Vec<_> = iter::repeat(' ').take(plot_w * plot_h).collect();

        let t_start = 1.0;
        let t_end = 2.0;
        let steps = 10;
        let step_size = (t_end - t_start) / steps as f32;
        for s in 0..steps {
            let t = step_size * s as f32 + t_start;
            println!("t = {}", t);
            let x = spline.point(t);
            println!("x = {:?}", x);
            if x.x > -1 && x.x < plot_w as i32 && x.y > -1 && x.y < plot_h as i32 {
                plot[(plot_h - 1 - x.y as usize) * plot_w + x.x as usize] = 'X';
            }
        }

        for y in 0..plot_h {
            for x in 0..plot_w {
                print!("{}", plot[y * plot_w + x]);
            }
            println!("");
        }
    }
}

<commit_msg>Trying to fix de boors<commit_after>use std::ops::{Mul, Add};

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Mul<f32, Output = T> + Add<Output = T> + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i - 1] <= t < knot[i]
        let i = match upper_bounds(&self.knots[self.degree - 1..self.knots.len() - self.degree], t) {
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        println!("Found i = {} for t = {}\n\tknots = {:?}", i, t, self.knots);
        println!("degree = {}", self.degree);
        self.de_boors(t, self.degree, i)
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is terrible,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            self.control_points[i]
        } else {
            println!("Looking at k = {}, i = {}, t = {}", k, i, t);
            println!("\tknots[i + self.degree + 1 - k] = {}, self.knots[i] = {}",
                     self.knots[i + self.degree + 1 - k], self.knots[i]);
            // TODO: This is still broken
            let alpha = (t - self.knots[i]) / (self.knots[i + self.degree + 1 - k] - self.knots[i]);
            self.de_boors(t, k - 1, i - 1) * (1.0 - alpha) + self.de_boors(t, k - 1, i) * alpha
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};
    use std::iter;

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    #[derive(Copy, Clone, Debug)]
    struct Pointi {
        x: i32,
        y: i32,
    }
    impl Pointi {
        fn new(x: i32, y: i32) -> Pointi {
            Pointi { x: x, y: y }
        }
    }
    impl Mul<f32> for Pointi {
        type Output = Pointi;
        fn mul(self, rhs: f32) -> Pointi {
            Pointi { x: (self.x as f32 * rhs) as i32,
                    y: (self.y as f32 * rhs) as i32 }
        }
    }
    impl Add for Pointi {
        type Output = Pointi;
        fn add(self, rhs: Pointi) -> Pointi {
            Pointi { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    #[test]
    fn linear_bspline(){
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }

    #[test]
    fn bspline_plot(){
        let points = vec![Pointi::new(0, 5), Pointi::new(20, 20), Pointi::new(39, 5)];
        let knots = vec![0.0, 0.0, 0.5, 2.5, 3.0, 3.0];

        // TODO: This doesn't compute or plot the correct curve
        let plot_w = 40;
        let plot_h = 40;
        let mut plot: Vec<_> = iter::repeat(' ').take(plot_w * plot_h).collect();

        plot[(plot_h - 1 - points[0].y as usize) * plot_w + points[0].x as usize] = 'S';
        plot[(plot_h - 1 - points[1].y as usize) * plot_w + points[1].x as usize] = 'C';
        plot[(plot_h - 1 - points[2].y as usize) * plot_w + points[2].x as usize] = 'E';

        let spline = BSpline::new(2, points, knots);

        let t_start = 1.0;
        let t_end = 2.0;
        let steps = 50;
        let step_size = (t_end - t_start) / steps as f32;
        for s in 0..steps {
            let t = step_size * s as f32 + t_start;
            println!("t = {}", t);
            let x = spline.point(t);
            println!("x = {:?}", x);
            if x.x > -1 && x.x < plot_w as i32 && x.y > -1 && x.y < plot_h as i32 {
                plot[(plot_h - 1 - x.y as usize) * plot_w + x.x as usize] = 'X';
            }
        }

        for y in 0..plot_h {
            for x in 0..plot_w {
                print!("{}", plot[y * plot_w + x]);
            }
            println!("");
        }
    }
}

<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new(Arc::new(io));
//! 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::thread;
use std::sync::Arc;
use std::io::Read;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
}

impl ServerHandler {
	/// Create new request handler.
	fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler for ServerHandler {
	fn handle(&self, mut req: hyper::server::Request, mut res: hyper::server::Response) {
		match req.method {
			Method::Options => {
				*res.headers_mut() = self.response_headers();
			},
			Method::Post => {
				let mut body = String::new();
				if let Err(_) = req.read_to_string(&mut body) {
					// TODO: return proper jsonrpc error instead
					*res.status_mut() = hyper::status::StatusCode::MethodNotAllowed;
					return;
				}
				if let Some(response) = self.jsonrpc_handler.handle_request(&body) {
					*res.headers_mut() = self.response_headers();
					res.send(response.as_ref()).unwrap();
				}
			},
			_ => *res.status_mut() = hyper::status::StatusCode::MethodNotAllowed
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let server = Server::new(Arc::new(io));
/// 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
/// }
/// ```
pub struct Server {
	jsonrpc_handler: Arc<IoHandler>,
}

impl Server {
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		Server {
			jsonrpc_handler: jsonrpc_handler,
		}
	}

	pub fn start(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) {
		hyper::Server::http(addr).unwrap().handle_threads(ServerHandler::new(self.jsonrpc_handler.clone(), cors_domain), threads).unwrap();
	}

	pub fn start_async(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) {
		let address = addr.to_owned();
		let handler = self.jsonrpc_handler.clone();
		thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
			hyper::Server::http(address.as_ref() as &str).unwrap().handle_threads(ServerHandler::new(handler, cors_domain), threads).unwrap();
		}).unwrap();
	}
}
<commit_msg>Exposing<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new(Arc::new(io));
//! 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::thread;
use std::sync::Arc;
use std::io::Read;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler for ServerHandler {
	fn handle(&self, mut req: hyper::server::Request, mut res: hyper::server::Response) {
		match req.method {
			Method::Options => {
				*res.headers_mut() = self.response_headers();
			},
			Method::Post => {
				let mut body = String::new();
				if let Err(_) = req.read_to_string(&mut body) {
					// TODO: return proper jsonrpc error instead
					*res.status_mut() = hyper::status::StatusCode::MethodNotAllowed;
					return;
				}
				if let Some(response) = self.jsonrpc_handler.handle_request(&body) {
					*res.headers_mut() = self.response_headers();
					res.send(response.as_ref()).unwrap();
				}
			},
			_ => *res.status_mut() = hyper::status::StatusCode::MethodNotAllowed
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let server = Server::new(Arc::new(io));
/// 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
/// }
/// ```
pub struct Server {
	jsonrpc_handler: Arc<IoHandler>,
}

impl Server {
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		Server {
			jsonrpc_handler: jsonrpc_handler,
		}
	}

	pub fn start(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) {
		hyper::Server::http(addr).unwrap().handle_threads(ServerHandler::new(self.jsonrpc_handler.clone(), cors_domain), threads).unwrap();
	}

	pub fn start_async(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) {
		let address = addr.to_owned();
		let handler = self.jsonrpc_handler.clone();
		thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
			hyper::Server::http(address.as_ref() as &str).unwrap().handle_threads(ServerHandler::new(handler, cors_domain), threads).unwrap();
		}).unwrap();
	}
}
<|endoftext|>


<commit_before>use std::fmt::{self, Debug, Formatter};

/// A data-structure for storing a sequence of 4-bit values.
///
/// Values are stored in a `Vec<u8>`, with two values per byte.
///
/// Values at even indices are stored in the most-significant half of their byte,
/// while values at odd indices are stored in the least-significant half.
///
/// Imagine a vector of MSB bytes, and you'll be right.
///
/// n = [_ _ | _ _ | _ _]
///
/// # Invariants
/// * If the length is odd, then the second half of the last byte must be 0.
pub struct NibbleVec {
    length: usize,
    data: Vec<u8>
}

impl NibbleVec {
    /// Create an empty nibble vector.
    pub fn new() -> NibbleVec {
        NibbleVec {
            length: 0,
            data: Vec::new()
        }
    }

    /// Create a nibble vector from a vector of bytes.
    ///
    /// Each byte is split into two 4-bit entries (MSB, LSB).
    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            length: length,
            data: vec
        }
    }

    /// Get the number of elements stored in the vector.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Fetch a single entry from the vector.
    ///
    /// Guaranteed to be a value in the interval [0, 15].
    ///
    /// **Panics** if `idx >= self.len()`.
    pub fn get(&self, idx: usize) -> u8 {
        if idx >= self.length {
            panic!("attempted access beyond vector end. len is {}, index is {}", self.length, idx);
        }
        let vec_idx = idx / 2;
        match idx % 2 {
            // If the index is even, take the first (most significant) half of the stored byte.
            0 => self.data[vec_idx] >> 4,
            // If the index is odd, take the second (least significant) half.
            _ => self.data[vec_idx] & 0x0F
        }
    }

    /// Add a single nibble to the vector.
    ///
    /// Only the 4 least-significant bits of the value are used.
    pub fn push(&mut self, val: u8) {
        if self.length % 2 == 0 {
            self.data.push(val << 4);
        } else {
            let vec_len = self.data.len();

            // Zero the second half of the last byte just to be safe.
            self.data[vec_len - 1] &= 0xF0;

            // Write the new value.
            self.data[vec_len - 1] |= val & 0x0F;
        }
        self.length += 1;
    }

    /// Split the vector into two parts.
    ///
    /// All elements at or following the given index are returned in a new `NibbleVec`,
    /// with exactly `idx` elements remaining in this vector.
    ///
    /// **Panics** if `idx > self.len()`.
    pub fn split(&mut self, idx: usize) -> NibbleVec {
        if idx > self.length {
            panic!("attempted to split past vector end. len is {}, index is {}", self.length, idx);
        } else if idx == self.length {
            NibbleVec::new()
        } else if idx % 2 == 0 {
            self.split_even(idx)
        } else {
            self.split_odd(idx)
        }
    }

    /// Split function for odd *indices*.
    #[inline(always)]
    fn split_odd(&mut self, idx: usize) -> NibbleVec {
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Perform an overlap copy, copying the last nibble of the original vector only if
        // the length of the new tail is *odd*.
        let tail_length = self.length - idx;
        let take_last = tail_length % 2 == 1;
        self.overlap_copy(idx / 2, self.data.len(), &mut tail.data, &mut tail.length, take_last);

        // Remove the copied bytes, being careful to skip the idx byte.
        for _ in range(idx / 2 + 1, self.data.len()) {
            self.data.pop();
        }

        // Zero the second half of the index byte so as to maintain the last-nibble invariant.
        self.data[idx / 2] &= 0xF0;

        // Update the length of the first NibbleVec.
        self.length = idx;

        tail
    }

    /// Split function for even *indices*.
    #[inline(always)]
    fn split_even(&mut self, idx: usize) -> NibbleVec {
        // Avoid allocating a temporary vector by copying all the bytes in order, then popping them.

        // Possible to prove: l_d - ⌊i / 2⌋ = ⌊(l_v - i + 1) / 2⌋
        //  where l_d = self.data.len()
        //        l_v = self.length
        let tail_vec_size = (self.length - idx + 1) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Copy the bytes.
        for i in range(idx / 2, self.data.len()) {
            tail.data.push(self.data[i]);
        }

        // Pop the same bytes.
        for _ in range(idx / 2, self.data.len()) {
            self.data.pop();
        }

        // Update lengths.
        tail.length = self.length - idx;
        self.length = idx;

        tail
    }

    /// Copy data between the second half of self.data[start] and
    /// self.data[end - 1]. The second half of the last entry is included
    /// if include_last is true.
    #[inline(always)]
    fn overlap_copy(&self, start: usize, end: usize, vec: &mut Vec<u8>, length: &mut usize, include_last: bool) {
        // Copy up to the first half of the last byte.
        for i in range(start, end - 1) {
            // The first half is the second half of the old entry.
            let first_half = self.data[i] & 0x0f;

            // The second half is the first half of the next entry.
            let second_half = self.data[i + 1] >> 4;

            vec.push((first_half << 4) | second_half);
            *length += 2;
        }

        if include_last {
            let last = self.data[end - 1] & 0x0f;
            vec.push(last << 4);
            *length += 1;
        }
    }

    /// Append another nibble vector.
    pub fn join(mut self, other: &NibbleVec) -> NibbleVec {
        // If the length is even, we can append directly.
        if self.length % 2 == 0 {
            self.length += other.length;
            self.data.push_all(other.data.as_slice());
            return self;
        }

        // If the other vector is empty, bail out.
        if other.len() == 0 {
            return self;
        }

        // If the length is odd, we have to perform an overlap copy.
        // Copy the first half of the first element, to make the vector an even length.
        self.push(other.get(0));

        // Copy the rest of the vector using an overlap copy.
        let take_last = other.len() % 2 == 0;
        other.overlap_copy(0, other.data.len(), &mut self.data, &mut self.length, take_last);

        self
    }
}

impl PartialEq<NibbleVec> for NibbleVec {
    fn eq(&self, other: &NibbleVec) -> bool {
        self.length == other.length &&
        self.data == other.data
    }
}

impl Eq for NibbleVec {}

impl PartialEq<[u8]> for NibbleVec {
    fn eq(&self, other: &[u8]) -> bool {
        if other.len() != self.len() {
            return false;
        }

        for (i, x) in other.iter().enumerate() {
            if self.get(i) != *x {
                return false;
            }
        }
        true
    }
}

impl Clone for NibbleVec {
    fn clone(&self) -> NibbleVec {
        NibbleVec {
            length: self.length,
            data: self.data.clone()
        }
    }
}

impl Debug for NibbleVec {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "NibbleVec ["));

        if self.len() > 0 {
            try!(write!(fmt, "{}", self.get(0)));
        }

        for i in range(1, self.len()) {
            try!(write!(fmt, ", {}", self.get(i)));
        }
        write!(fmt, "]")
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    fn v8_7_6_5() -> NibbleVec {
        NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
    }

    fn v11_10_9() -> NibbleVec {
        let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
        result.push(9);
        result
    }

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![3 << 4 | 7]);
        assert_eq!(nv.get(0), 3u8);
        assert_eq!(nv.get(1), 7u8);
    }

    #[test]
    fn push() {
        let mut nv = NibbleVec::new();
        let data = vec![0, 1, 3, 5, 7, 9, 11, 15];
        for val in data.iter() {
            nv.push(*val);
        }

        for (i, val) in data.iter().enumerate() {
            assert_eq!(nv.get(i), *val);
        }
    }

    fn split_test(  nibble_vec: &NibbleVec,
                    idx: usize,
                    first: Vec<u8>,
                    second: Vec<u8>) {
        let mut init = nibble_vec.clone();
        let tail = init.split(idx);
        assert!(init == first[..]);
        assert!(tail == second[..]);
    }

    #[test]
    fn split_even_length() {
        let even_length = v8_7_6_5();
        split_test(&even_length, 0, vec![], vec![8, 7, 6, 5]);
        split_test(&even_length, 1, vec![8], vec![7, 6, 5]);
        split_test(&even_length, 2, vec![8, 7], vec![6, 5]);
        split_test(&even_length, 4, vec![8, 7, 6, 5], vec![]);
    }

    #[test]
    fn split_odd_length() {
        let odd_length = v11_10_9();
        split_test(&odd_length, 0, vec![], vec![11, 10, 9]);
        split_test(&odd_length, 1, vec![11], vec![10, 9]);
        split_test(&odd_length, 2, vec![11, 10], vec![9]);
        split_test(&odd_length, 3, vec![11, 10, 9], vec![]);
    }

    /// Join vec2 onto vec1 and ensure that the results matches the one expected.
    fn join_test(vec1: &NibbleVec, vec2: &NibbleVec, result: Vec<u8>) {
        let joined = vec1.clone().join(vec2);
        assert!(joined == result[..]);
    }

    #[test]
    fn join_even_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v1, &v2, vec![8, 7, 6, 5, 11, 10, 9]);
        join_test(&v1, &v1, vec![8, 7, 6, 5, 8, 7, 6, 5]);
        join_test(&v1, &NibbleVec::new(), vec![8, 7, 6, 5]);
        join_test(&NibbleVec::new(), &v1, vec![8, 7, 6, 5]);
    }

    #[test]
    fn join_odd_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v2, &v1, vec![11, 10, 9, 8, 7, 6, 5]);
        join_test(&v2, &v2, vec![11, 10, 9, 11, 10, 9]);
        join_test(&v2, &NibbleVec::new(), vec![11, 10, 9]);
    }

    /// Ensure that the last nibble is zeroed before reuse.
    #[test]
    fn memory_reuse() {
        let mut vec = NibbleVec::new();
        vec.push(10);
        vec.push(1);

        // Pushing.
        vec.split(1);
        vec.push(2);
        assert_eq!(vec.get(1), 2);

        // Joining.
        vec.split(1);
        vec = vec.join(&NibbleVec::from_byte_vec(vec![1 << 4 | 3, 5 << 4]));
        assert_eq!(vec.get(1), 1);
    }
}
<commit_msg>Silence warnings about range usage.<commit_after>#![feature(core, collections)]

use std::fmt::{self, Debug, Formatter};

/// A data-structure for storing a sequence of 4-bit values.
///
/// Values are stored in a `Vec<u8>`, with two values per byte.
///
/// Values at even indices are stored in the most-significant half of their byte,
/// while values at odd indices are stored in the least-significant half.
///
/// Imagine a vector of MSB bytes, and you'll be right.
///
/// n = [_ _ | _ _ | _ _]
///
/// # Invariants
/// * If the length is odd, then the second half of the last byte must be 0.
pub struct NibbleVec {
    length: usize,
    data: Vec<u8>
}

impl NibbleVec {
    /// Create an empty nibble vector.
    pub fn new() -> NibbleVec {
        NibbleVec {
            length: 0,
            data: Vec::new()
        }
    }

    /// Create a nibble vector from a vector of bytes.
    ///
    /// Each byte is split into two 4-bit entries (MSB, LSB).
    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            length: length,
            data: vec
        }
    }

    /// Get the number of elements stored in the vector.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Fetch a single entry from the vector.
    ///
    /// Guaranteed to be a value in the interval [0, 15].
    ///
    /// **Panics** if `idx >= self.len()`.
    pub fn get(&self, idx: usize) -> u8 {
        if idx >= self.length {
            panic!("attempted access beyond vector end. len is {}, index is {}", self.length, idx);
        }
        let vec_idx = idx / 2;
        match idx % 2 {
            // If the index is even, take the first (most significant) half of the stored byte.
            0 => self.data[vec_idx] >> 4,
            // If the index is odd, take the second (least significant) half.
            _ => self.data[vec_idx] & 0x0F
        }
    }

    /// Add a single nibble to the vector.
    ///
    /// Only the 4 least-significant bits of the value are used.
    pub fn push(&mut self, val: u8) {
        if self.length % 2 == 0 {
            self.data.push(val << 4);
        } else {
            let vec_len = self.data.len();

            // Zero the second half of the last byte just to be safe.
            self.data[vec_len - 1] &= 0xF0;

            // Write the new value.
            self.data[vec_len - 1] |= val & 0x0F;
        }
        self.length += 1;
    }

    /// Split the vector into two parts.
    ///
    /// All elements at or following the given index are returned in a new `NibbleVec`,
    /// with exactly `idx` elements remaining in this vector.
    ///
    /// **Panics** if `idx > self.len()`.
    pub fn split(&mut self, idx: usize) -> NibbleVec {
        if idx > self.length {
            panic!("attempted to split past vector end. len is {}, index is {}", self.length, idx);
        } else if idx == self.length {
            NibbleVec::new()
        } else if idx % 2 == 0 {
            self.split_even(idx)
        } else {
            self.split_odd(idx)
        }
    }

    /// Split function for odd *indices*.
    #[inline(always)]
    fn split_odd(&mut self, idx: usize) -> NibbleVec {
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Perform an overlap copy, copying the last nibble of the original vector only if
        // the length of the new tail is *odd*.
        let tail_length = self.length - idx;
        let take_last = tail_length % 2 == 1;
        self.overlap_copy(idx / 2, self.data.len(), &mut tail.data, &mut tail.length, take_last);

        // Remove the copied bytes, being careful to skip the idx byte.
        for _ in range(idx / 2 + 1, self.data.len()) {
            self.data.pop();
        }

        // Zero the second half of the index byte so as to maintain the last-nibble invariant.
        self.data[idx / 2] &= 0xF0;

        // Update the length of the first NibbleVec.
        self.length = idx;

        tail
    }

    /// Split function for even *indices*.
    #[inline(always)]
    fn split_even(&mut self, idx: usize) -> NibbleVec {
        // Avoid allocating a temporary vector by copying all the bytes in order, then popping them.

        // Possible to prove: l_d - ⌊i / 2⌋ = ⌊(l_v - i + 1) / 2⌋
        //  where l_d = self.data.len()
        //        l_v = self.length
        let tail_vec_size = (self.length - idx + 1) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Copy the bytes.
        for i in range(idx / 2, self.data.len()) {
            tail.data.push(self.data[i]);
        }

        // Pop the same bytes.
        for _ in range(idx / 2, self.data.len()) {
            self.data.pop();
        }

        // Update lengths.
        tail.length = self.length - idx;
        self.length = idx;

        tail
    }

    /// Copy data between the second half of self.data[start] and
    /// self.data[end - 1]. The second half of the last entry is included
    /// if include_last is true.
    #[inline(always)]
    fn overlap_copy(&self, start: usize, end: usize, vec: &mut Vec<u8>, length: &mut usize, include_last: bool) {
        // Copy up to the first half of the last byte.
        for i in range(start, end - 1) {
            // The first half is the second half of the old entry.
            let first_half = self.data[i] & 0x0f;

            // The second half is the first half of the next entry.
            let second_half = self.data[i + 1] >> 4;

            vec.push((first_half << 4) | second_half);
            *length += 2;
        }

        if include_last {
            let last = self.data[end - 1] & 0x0f;
            vec.push(last << 4);
            *length += 1;
        }
    }

    /// Append another nibble vector.
    pub fn join(mut self, other: &NibbleVec) -> NibbleVec {
        // If the length is even, we can append directly.
        if self.length % 2 == 0 {
            self.length += other.length;
            self.data.push_all(other.data.as_slice());
            return self;
        }

        // If the other vector is empty, bail out.
        if other.len() == 0 {
            return self;
        }

        // If the length is odd, we have to perform an overlap copy.
        // Copy the first half of the first element, to make the vector an even length.
        self.push(other.get(0));

        // Copy the rest of the vector using an overlap copy.
        let take_last = other.len() % 2 == 0;
        other.overlap_copy(0, other.data.len(), &mut self.data, &mut self.length, take_last);

        self
    }
}

impl PartialEq<NibbleVec> for NibbleVec {
    fn eq(&self, other: &NibbleVec) -> bool {
        self.length == other.length &&
        self.data == other.data
    }
}

impl Eq for NibbleVec {}

impl PartialEq<[u8]> for NibbleVec {
    fn eq(&self, other: &[u8]) -> bool {
        if other.len() != self.len() {
            return false;
        }

        for (i, x) in other.iter().enumerate() {
            if self.get(i) != *x {
                return false;
            }
        }
        true
    }
}

impl Clone for NibbleVec {
    fn clone(&self) -> NibbleVec {
        NibbleVec {
            length: self.length,
            data: self.data.clone()
        }
    }
}

impl Debug for NibbleVec {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "NibbleVec ["));

        if self.len() > 0 {
            try!(write!(fmt, "{}", self.get(0)));
        }

        for i in range(1, self.len()) {
            try!(write!(fmt, ", {}", self.get(i)));
        }
        write!(fmt, "]")
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    fn v8_7_6_5() -> NibbleVec {
        NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
    }

    fn v11_10_9() -> NibbleVec {
        let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
        result.push(9);
        result
    }

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![3 << 4 | 7]);
        assert_eq!(nv.get(0), 3u8);
        assert_eq!(nv.get(1), 7u8);
    }

    #[test]
    fn push() {
        let mut nv = NibbleVec::new();
        let data = vec![0, 1, 3, 5, 7, 9, 11, 15];
        for val in data.iter() {
            nv.push(*val);
        }

        for (i, val) in data.iter().enumerate() {
            assert_eq!(nv.get(i), *val);
        }
    }

    fn split_test(  nibble_vec: &NibbleVec,
                    idx: usize,
                    first: Vec<u8>,
                    second: Vec<u8>) {
        let mut init = nibble_vec.clone();
        let tail = init.split(idx);
        assert!(init == first[..]);
        assert!(tail == second[..]);
    }

    #[test]
    fn split_even_length() {
        let even_length = v8_7_6_5();
        split_test(&even_length, 0, vec![], vec![8, 7, 6, 5]);
        split_test(&even_length, 1, vec![8], vec![7, 6, 5]);
        split_test(&even_length, 2, vec![8, 7], vec![6, 5]);
        split_test(&even_length, 4, vec![8, 7, 6, 5], vec![]);
    }

    #[test]
    fn split_odd_length() {
        let odd_length = v11_10_9();
        split_test(&odd_length, 0, vec![], vec![11, 10, 9]);
        split_test(&odd_length, 1, vec![11], vec![10, 9]);
        split_test(&odd_length, 2, vec![11, 10], vec![9]);
        split_test(&odd_length, 3, vec![11, 10, 9], vec![]);
    }

    /// Join vec2 onto vec1 and ensure that the results matches the one expected.
    fn join_test(vec1: &NibbleVec, vec2: &NibbleVec, result: Vec<u8>) {
        let joined = vec1.clone().join(vec2);
        assert!(joined == result[..]);
    }

    #[test]
    fn join_even_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v1, &v2, vec![8, 7, 6, 5, 11, 10, 9]);
        join_test(&v1, &v1, vec![8, 7, 6, 5, 8, 7, 6, 5]);
        join_test(&v1, &NibbleVec::new(), vec![8, 7, 6, 5]);
        join_test(&NibbleVec::new(), &v1, vec![8, 7, 6, 5]);
    }

    #[test]
    fn join_odd_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v2, &v1, vec![11, 10, 9, 8, 7, 6, 5]);
        join_test(&v2, &v2, vec![11, 10, 9, 11, 10, 9]);
        join_test(&v2, &NibbleVec::new(), vec![11, 10, 9]);
    }

    /// Ensure that the last nibble is zeroed before reuse.
    #[test]
    fn memory_reuse() {
        let mut vec = NibbleVec::new();
        vec.push(10);
        vec.push(1);

        // Pushing.
        vec.split(1);
        vec.push(2);
        assert_eq!(vec.get(1), 2);

        // Joining.
        vec.split(1);
        vec = vec.join(&NibbleVec::from_byte_vec(vec![1 << 4 | 3, 5 << 4]));
        assert_eq!(vec.get(1), 1);
    }
}
<|endoftext|>