<commit_before>//! The main user interface from which the user will define systems to create.
//! They can also access and modify the `DataBase` of components to use in their
//! systems.
//!
//! This is implemented as a *very* basic text interface. This could be improved
//! greatly by knowing more about human interface design. In particular the systems
//! for creating `SheetConfEntry` and `SystemDefinition` are in need of improvement.

#[macro_use] pub mod utils;
mod edit_database;
mod define_components;

use super::Config;
use error::Result;
use output;

use grafen::coord::Coord;
use grafen::database::AvailableComponents;
use grafen::describe::{describe_list, Describe};
use grafen::system::{Component, ResidueBase};
use std::error::Error;

#[derive(Debug)]
/// A `Component` which has been constructed along with a descriptive string.
pub struct ConstructedComponent {
    /// Description of the component.
    description: String,
    /// The component.
    pub component: Component,
}

impl Describe for ConstructedComponent {
    fn describe(&self) -> String {
        format!("{} ({} residues at {})",
            self.description,
            self.component.num_residues(),
            self.component.origin)
    }
}

#[derive(Debug)]
/// All `ConstructedComponent`s and `ComponentDefinition`s are kept in this
/// `System` which keeps track of those and other meta information.
pub struct System {
    /// System box size. Either set by the user or calculated from the components.
    pub box_size: Option<Coord>,
    /// Component definitions.
    pub definitions: Vec<AvailableComponents>,
    /// Components and their descriptions belonging to the system.
    pub constructed: Vec<ConstructedComponent>,
}

impl System {
    /// Calculate the box size from the system components. The largest extension along each
    /// direction is used for the final box size.
    ///
    /// Returns None if no components exist in the system.
    pub fn calc_box_size(&self) -> Option<Coord> {
        if self.constructed.is_empty() {
            return None;
        }

        let box_size = self.constructed.iter().fold(
            Coord::new(0.0, 0.0, 0.0), |acc, conf| {
                let (x1, y1, z1) = acc.to_tuple();
                let (x2, y2, z2) = conf.component.box_size.to_tuple();

                Coord::new(x1.max(x2), y1.max(y2), z1.max(z2))
            }
        );

        Some(box_size)
    }

    /// Describe the current system.
    fn describe(&self) {
        eprintln!("{}", describe_list("Defined components", &self.definitions));
        eprintln!("{}", describe_list("Constructed components", &self.constructed));
    }

    /// Iterate over the residues in a `System`.
    /// Yields the `Coord` and `ResidueBase` for each residue, as the tuple `CoordAndResidue`.
    pub fn iter_residues(&self) -> ResidueIter {
        CoordsAndResiduesIterator::new(&self.constructed)
    }

    /// Calculate the number of atoms in the system.
    pub fn num_atoms(&self) -> usize {
        self.constructed.iter().map(|conf| {
            conf.component.residue_base.atoms.len() * conf.component.residue_coords.len()
        }).sum()
    }
}

/// We want to be able to iterate over all residues in a `System`.
/// To do this we use as custom `Iterator` which yields every residue's
/// `Coord` and `ResidueBase`.
struct CoordsAndResiduesIterator<'a> {
    components: &'a [ConstructedComponent],
    current_component: usize,
    current_coord: usize,
}

/// Construct it from a list of components.
impl<'a> CoordsAndResiduesIterator<'a> {
    fn new(components: &[ConstructedComponent]) -> Box<CoordsAndResiduesIterator> {
        Box::new(CoordsAndResiduesIterator {
            components: &components,
            current_component: 0,
            current_coord: 0,
        })
    }
}

// Newtypes for the iterator.
type CoordAndResidue<'a> = (Coord, &'a ResidueBase);
// TODO: This should use `impl Trait` once that is in Rust stable.
type ResidueIter<'a> = Box<Iterator<Item = CoordAndResidue<'a>> + 'a>;

impl<'a> Iterator for CoordsAndResiduesIterator<'a> {
    type Item = CoordAndResidue<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(cons_component) = self.components.get(self.current_component) {
                let component = &cons_component.component;

                if let Some(&coord) = component.residue_coords.get(self.current_coord) {
                    self.current_coord += 1;
                    return Some((component.origin + coord, &component.residue_base));
                } else {
                    self.current_component += 1;
                    self.current_coord = 0;
                }
            } else {
                return None;
            }
        }
    }
}

#[derive(Clone, Copy, Debug)]
/// User commands for defining the system.
enum MainMenu {
    DefineComponents,
    ConstructComponents,
    EditDatabase,
    SaveSystem,
    Quit,
}
use self::MainMenu::*;

/// Loop over a menu in which the user can define the system which will be created, etc.
///
/// The idea of this interface is relatively simple:
///
/// 1. The user reads or constructs a `DataBase` of residues (`ResidueBase`).
/// 2. Then constructs definitions of substrates or objects to be created (can also be
///    saved to and read from the `DataBase`).
/// 3. Processes these definitions to create the actual components which make up the system.
/// 4. Modifies or transforms these components by copying, translating, rotating etc.
/// 5. Finally saves the full system to disk.
///
/// Modifying the `DataBase`, setting the definitions `SheetConf` and editing the
/// `Component`s each require a separate menu, accessed from this super menu.
/// This menu should also allow the user to save the system to disk, set its name
/// and file path and any other possible options.
pub fn user_menu(mut config: &mut Config) -> Result<()> {
    let mut system = System { box_size: None, constructed: vec![], definitions: vec![] };

    let (commands, item_texts) = create_menu_items![
        (DefineComponents, "Define the list of components to construct"),
        (ConstructComponents, "Construct components from all definitions"),
        (EditDatabase, "Edit the database of residue and object definitions"),
        (SaveSystem, "Save the constructed components to disk as a system"),
        (Quit, "Quit the program")
    ];

    loop {
        system.describe();
        let command = utils::select_command(item_texts, commands)?;

        let result = match command {
            DefineComponents => {
                define_components::user_menu(&config.database, &mut system.definitions)
                    .map(|_| "Finished editing list of definitions".to_string())
            },
            ConstructComponents => {
                construct_components(&mut system)
                    .map(|_| "Successfully constructed all components".to_string())
            },
            EditDatabase => {
                edit_database::user_menu(&mut config.database)
            },
            SaveSystem => {
                output::write_gromos(&system, &config)
                    .map(|_| "Saved system to disk".to_string())
            },
            Quit => {
                return Ok(());
            },
        };

        match result {
            Ok(msg) => { eprintln!("{}", msg); },
            Err(err) => { eprintln!("error: {}", err.description()); },
        }

        eprintln!("");
    }
}

fn construct_components(system: &mut System) -> Result<()> {
    for def in system.definitions.drain(..) {
        let description = def.describe();
        let component = def.into_component()?;

        system.constructed.push(ConstructedComponent{ description, component });
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use grafen::system::{Atom, ResidueBase};

    /// Setup the base residues.
    /// base_one: two atoms
    /// base_two: one atom
    fn setup_base_residues() -> (ResidueBase, ResidueBase) {
        let base_one = ResidueBase {
            code: "R1".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(0.0, 2.0, 1.0) }
                ],
            };
        let base_two = ResidueBase {
            code: "R2".to_string(),
            atoms: vec![
                Atom { code: "B".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                ],
            };

        (base_one, base_two)
    }

    /// Setup a system of three components and in total four residues / seven atoms:
    ///     0. base_one, 2 atoms
    ///     1. base_two, 1 atom
    ///     2. base_one, 2 atoms
    ///     3. base_one, 2 atoms
    fn setup_system() -> System {
        let (base_one, base_two) = setup_base_residues();

        System {
            box_size: None,
            definitions: vec![],
            constructed: vec![
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along x
                        box_size: Coord::new(10.0, 1.0, 0.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_one.clone(),
                        // 1 residue * 2 atoms per residue
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0)],
                    },
                },
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along z
                        box_size: Coord::new(1.0, 1.0, 7.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_two.clone(),
                        // 1 * 1 atoms
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0)],
                    },
                },
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along y
                        box_size: Coord::new(1.0, 5.0, 0.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_one.clone(),
                        // 2 * 2 atoms
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0), Coord::new(1.0, 0.0, 0.0)],
                    },
                },
            ]
        }
    }

    #[test]
    fn all_atoms_are_counted_in_system() {
        let system = setup_system();

        assert_eq!(7, system.num_atoms());
    }

    #[test]
    fn box_size_is_largest_in_each_direction() {
        let system = setup_system();
        assert_eq!(Some(Coord::new(10.0, 5.0, 7.0)), system.calc_box_size());
    }

    #[test]
    fn box_size_is_none_if_no_components() {
        let system = System {
            box_size: None,
            definitions: vec![],
            constructed: vec![],
        };

        assert!(system.calc_box_size().is_none());
    }

    #[test]
    fn iterate_over_system_residues() {
        let (base_one, base_two) = setup_base_residues();
        let system = setup_system();

        let mut iter = system.iter_residues();
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_two)), iter.next());
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(Some((Coord::new(1.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn iter_residues_adds_component_origin() {
        let origin = Coord::new(-5.0, 10.0, 5.0);
        let coord1 = Coord::new(0.0, 0.0, 0.0);
        let coord2 = Coord::new(1.0, 1.0, 1.0);

        let (base_one, _) = setup_base_residues();
        let system = System {
            box_size: None,
            definitions: vec![],
            constructed: vec![
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        box_size: Coord::ORIGO,
                        origin: origin,
                        residue_base: base_one.clone(),
                        residue_coords: vec![coord1, coord2],
                    },
                },
            ]
        };

        let mut iter = system.iter_residues();
        assert_eq!(Some((origin + coord1, &base_one)), iter.next());
        assert_eq!(Some((origin + coord2, &base_one)), iter.next());
        assert_eq!(None, iter.next());
    }
}
<commit_msg>The output system box size now accounts for component origin position, not just their size<commit_after>//! The main user interface from which the user will define systems to create.
//! They can also access and modify the `DataBase` of components to use in their
//! systems.
//!
//! This is implemented as a *very* basic text interface. This could be improved
//! greatly by knowing more about human interface design. In particular the systems
//! for creating `SheetConfEntry` and `SystemDefinition` are in need of improvement.

#[macro_use] pub mod utils;
mod edit_database;
mod define_components;

use super::Config;
use error::Result;
use output;

use grafen::coord::Coord;
use grafen::database::AvailableComponents;
use grafen::describe::{describe_list, Describe};
use grafen::system::{Component, ResidueBase};
use std::error::Error;

#[derive(Debug)]
/// A `Component` which has been constructed along with a descriptive string.
pub struct ConstructedComponent {
    /// Description of the component.
    description: String,
    /// The component.
    pub component: Component,
}

impl Describe for ConstructedComponent {
    fn describe(&self) -> String {
        format!("{} ({} residues at {})",
            self.description,
            self.component.num_residues(),
            self.component.origin)
    }
}

#[derive(Debug)]
/// All `ConstructedComponent`s and `ComponentDefinition`s are kept in this
/// `System` which keeps track of those and other meta information.
pub struct System {
    /// System box size. Either set by the user or calculated from the components.
    pub box_size: Option<Coord>,
    /// Component definitions.
    pub definitions: Vec<AvailableComponents>,
    /// Components and their descriptions belonging to the system.
    pub constructed: Vec<ConstructedComponent>,
}

impl System {
    /// Calculate the box size from the system components. The largest extension along each
    /// direction is used for the final box size.
    ///
    /// Returns None if no components exist in the system.
    pub fn calc_box_size(&self) -> Option<Coord> {
        if self.constructed.is_empty() {
            return None;
        }

        let box_size = self.constructed.iter().fold(
            Coord::new(0.0, 0.0, 0.0), |acc, conf| {
                let (x1, y1, z1) = acc.to_tuple();
                let (x2, y2, z2) = (conf.component.box_size + conf.component.origin).to_tuple();

                Coord::new(x1.max(x2), y1.max(y2), z1.max(z2))
            }
        );

        Some(box_size)
    }

    /// Describe the current system.
    fn describe(&self) {
        eprintln!("{}", describe_list("Defined components", &self.definitions));
        eprintln!("{}", describe_list("Constructed components", &self.constructed));
    }

    /// Iterate over the residues in a `System`.
    /// Yields the `Coord` and `ResidueBase` for each residue, as the tuple `CoordAndResidue`.
    pub fn iter_residues(&self) -> ResidueIter {
        CoordsAndResiduesIterator::new(&self.constructed)
    }

    /// Calculate the number of atoms in the system.
    pub fn num_atoms(&self) -> usize {
        self.constructed.iter().map(|conf| {
            conf.component.residue_base.atoms.len() * conf.component.residue_coords.len()
        }).sum()
    }
}

/// We want to be able to iterate over all residues in a `System`.
/// To do this we use as custom `Iterator` which yields every residue's
/// `Coord` and `ResidueBase`.
struct CoordsAndResiduesIterator<'a> {
    components: &'a [ConstructedComponent],
    current_component: usize,
    current_coord: usize,
}

/// Construct it from a list of components.
impl<'a> CoordsAndResiduesIterator<'a> {
    fn new(components: &[ConstructedComponent]) -> Box<CoordsAndResiduesIterator> {
        Box::new(CoordsAndResiduesIterator {
            components: &components,
            current_component: 0,
            current_coord: 0,
        })
    }
}

// Newtypes for the iterator.
type CoordAndResidue<'a> = (Coord, &'a ResidueBase);
// TODO: This should use `impl Trait` once that is in Rust stable.
type ResidueIter<'a> = Box<Iterator<Item = CoordAndResidue<'a>> + 'a>;

impl<'a> Iterator for CoordsAndResiduesIterator<'a> {
    type Item = CoordAndResidue<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(cons_component) = self.components.get(self.current_component) {
                let component = &cons_component.component;

                if let Some(&coord) = component.residue_coords.get(self.current_coord) {
                    self.current_coord += 1;
                    return Some((component.origin + coord, &component.residue_base));
                } else {
                    self.current_component += 1;
                    self.current_coord = 0;
                }
            } else {
                return None;
            }
        }
    }
}

#[derive(Clone, Copy, Debug)]
/// User commands for defining the system.
enum MainMenu {
    DefineComponents,
    ConstructComponents,
    EditDatabase,
    SaveSystem,
    Quit,
}
use self::MainMenu::*;

/// Loop over a menu in which the user can define the system which will be created, etc.
///
/// The idea of this interface is relatively simple:
///
/// 1. The user reads or constructs a `DataBase` of residues (`ResidueBase`).
/// 2. Then constructs definitions of substrates or objects to be created (can also be
///    saved to and read from the `DataBase`).
/// 3. Processes these definitions to create the actual components which make up the system.
/// 4. Modifies or transforms these components by copying, translating, rotating etc.
/// 5. Finally saves the full system to disk.
///
/// Modifying the `DataBase`, setting the definitions `SheetConf` and editing the
/// `Component`s each require a separate menu, accessed from this super menu.
/// This menu should also allow the user to save the system to disk, set its name
/// and file path and any other possible options.
pub fn user_menu(mut config: &mut Config) -> Result<()> {
    let mut system = System { box_size: None, constructed: vec![], definitions: vec![] };

    let (commands, item_texts) = create_menu_items![
        (DefineComponents, "Define the list of components to construct"),
        (ConstructComponents, "Construct components from all definitions"),
        (EditDatabase, "Edit the database of residue and object definitions"),
        (SaveSystem, "Save the constructed components to disk as a system"),
        (Quit, "Quit the program")
    ];

    loop {
        system.describe();
        let command = utils::select_command(item_texts, commands)?;

        let result = match command {
            DefineComponents => {
                define_components::user_menu(&config.database, &mut system.definitions)
                    .map(|_| "Finished editing list of definitions".to_string())
            },
            ConstructComponents => {
                construct_components(&mut system)
                    .map(|_| "Successfully constructed all components".to_string())
            },
            EditDatabase => {
                edit_database::user_menu(&mut config.database)
            },
            SaveSystem => {
                output::write_gromos(&system, &config)
                    .map(|_| "Saved system to disk".to_string())
            },
            Quit => {
                return Ok(());
            },
        };

        match result {
            Ok(msg) => { eprintln!("{}", msg); },
            Err(err) => { eprintln!("error: {}", err.description()); },
        }

        eprintln!("");
    }
}

fn construct_components(system: &mut System) -> Result<()> {
    for def in system.definitions.drain(..) {
        let description = def.describe();
        let component = def.into_component()?;

        system.constructed.push(ConstructedComponent{ description, component });
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use grafen::system::{Atom, ResidueBase};

    /// Setup the base residues.
    /// base_one: two atoms
    /// base_two: one atom
    fn setup_base_residues() -> (ResidueBase, ResidueBase) {
        let base_one = ResidueBase {
            code: "R1".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(0.0, 2.0, 1.0) }
                ],
            };
        let base_two = ResidueBase {
            code: "R2".to_string(),
            atoms: vec![
                Atom { code: "B".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                ],
            };

        (base_one, base_two)
    }

    /// Setup a system of three components and in total four residues / seven atoms:
    ///     0. base_one, 2 atoms
    ///     1. base_two, 1 atom
    ///     2. base_one, 2 atoms
    ///     3. base_one, 2 atoms
    fn setup_system() -> System {
        let (base_one, base_two) = setup_base_residues();

        System {
            box_size: None,
            definitions: vec![],
            constructed: vec![
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along x
                        box_size: Coord::new(10.0, 1.0, 0.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_one.clone(),
                        // 1 residue * 2 atoms per residue
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0)],
                    },
                },
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along z
                        box_size: Coord::new(1.0, 1.0, 7.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_two.clone(),
                        // 1 * 1 atoms
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0)],
                    },
                },
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        // Largest along y
                        box_size: Coord::new(1.0, 5.0, 0.0),
                        origin: Coord::new(0.0, 0.0, 0.0),
                        residue_base: base_one.clone(),
                        // 2 * 2 atoms
                        residue_coords: vec![Coord::new(0.0, 0.0, 0.0), Coord::new(1.0, 0.0, 0.0)],
                    },
                },
            ]
        }
    }

    #[test]
    fn all_atoms_are_counted_in_system() {
        let system = setup_system();

        assert_eq!(7, system.num_atoms());
    }

    #[test]
    fn box_size_is_largest_in_each_direction() {
        let system = setup_system();
        assert_eq!(Some(Coord::new(10.0, 5.0, 7.0)), system.calc_box_size());
    }

    #[test]
    fn box_size_accounts_for_component_origin() {
        let (base_one, _) = setup_base_residues();

        let system = System {
            box_size: None,
            definitions: vec![],
            constructed: vec![
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        box_size: Coord::new(1.0, 1.0, 1.0),
                        origin: Coord::new(1.0, 2.0, 3.0),
                        residue_base: base_one,
                        residue_coords: vec![],
                    },
                },
            ]
        };

        assert_eq!(Some(Coord::new(2.0, 3.0, 4.0)), system.calc_box_size());
    }

    #[test]
    fn box_size_is_none_if_no_components() {
        let system = System {
            box_size: None,
            definitions: vec![],
            constructed: vec![],
        };

        assert!(system.calc_box_size().is_none());
    }

    #[test]
    fn iterate_over_system_residues() {
        let (base_one, base_two) = setup_base_residues();
        let system = setup_system();

        let mut iter = system.iter_residues();
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_two)), iter.next());
        assert_eq!(Some((Coord::new(0.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(Some((Coord::new(1.0, 0.0, 0.0), &base_one)), iter.next());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn iter_residues_adds_component_origin() {
        let origin = Coord::new(-5.0, 10.0, 5.0);
        let coord1 = Coord::new(0.0, 0.0, 0.0);
        let coord2 = Coord::new(1.0, 1.0, 1.0);

        let (base_one, _) = setup_base_residues();
        let system = System {
            box_size: None,
            definitions: vec![],
            constructed: vec![
                ConstructedComponent {
                    description: "None".to_string(),
                    component: Component {
                        box_size: Coord::ORIGO,
                        origin: origin,
                        residue_base: base_one.clone(),
                        residue_coords: vec![coord1, coord2],
                    },
                },
            ]
        };

        let mut iter = system.iter_residues();
        assert_eq!(Some((origin + coord1, &base_one)), iter.next());
        assert_eq!(Some((origin + coord2, &base_one)), iter.next());
        assert_eq!(None, iter.next());
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

fn char_for_scancode(scancode: u8, shift: bool) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        if shift {
            character = SCANCODES[scancode as usize][1];
        } else {
            character = SCANCODES[scancode as usize][0];
        }
    }
    character
}

static SCANCODES: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<commit_msg>New field in Ps2 structure to choose the layout<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

fn char_for_scancode(scancode: u8, shift: bool) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        if shift {
            character = SCANCODES[scancode as usize][1];
        } else {
            character = SCANCODES[scancode as usize][0];
        }
    }
    character
}

static SCANCODES: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<|endoftext|>


<commit_before>use crate::index::diff::Error;
use crate::{Change, CrateVersion};
use bstr::BStr;
use git_repository as git;
use std::collections::BTreeSet;
use std::ops::Range;

#[derive(Default)]
pub(crate) struct Delegate {
    changes: Vec<Change>,
    delete_version_ids: BTreeSet<u64>,
    err: Option<Error>,
}

impl Delegate {
    pub fn handle(
        &mut self,
        change: git::object::tree::diff::Change<'_, '_, '_>,
    ) -> Result<git::object::tree::diff::Action, Error> {
        use git::bstr::ByteSlice;
        use git::object::tree::diff::change::Event::*;
        use git::objs::tree::EntryMode::*;
        fn entry_data(
            entry: git::objs::tree::EntryMode,
            id: git::Id<'_>,
        ) -> Result<Option<git::Object<'_>>, Error> {
            matches!(entry, Blob | BlobExecutable)
                .then(|| id.object())
                .transpose()
                .map_err(Into::into)
        }
        if change.location.contains(&b'.') {
            return Ok(Default::default());
        }
        match change.event {
            Addition { entry_mode, id } => {
                if let Some(obj) = entry_data(entry_mode, id)? {
                    for line in (&obj.data).lines() {
                        let version = version_from_json_line(line, change.location)?;
                        self.changes.push(if version.yanked {
                            Change::Yanked(version)
                        } else {
                            Change::Added(version)
                        });
                    }
                }
            }
            Deletion { entry_mode, .. } => {
                if entry_mode.is_no_tree() {
                    self.changes.push(Change::Deleted {
                        name: change.location.to_string(),
                    });
                }
            }
            Modification { .. } => {
                if let Some(diff) = change.event.diff().transpose()? {
                    let location = change.location;

                    let input = diff.line_tokens();
                    let mut err = None;
                    git::diff::blob::diff(
                        diff.algo,
                        &input,
                        |before: Range<u32>, after: Range<u32>| {
                            if err.is_some() {
                                return;
                            }
                            let mut lines_before = input.before
                                [before.start as usize..before.end as usize]
                                .iter()
                                .map(|&line| input.interner[line])
                                .peekable();
                            let mut lines_after = input.after
                                [after.start as usize..after.end as usize]
                                .iter()
                                .map(|&line| input.interner[line])
                                .peekable();
                            match (lines_before.peek().is_some(), lines_after.next().is_some()) {
                                (true, false) => {
                                    for removed in lines_before {
                                        match version_from_json_line(removed.as_bstr(), location) {
                                            Ok(version) => {
                                                self.delete_version_ids.insert(version.id());
                                            }
                                            Err(e) => {
                                                err = Some(e);
                                                break;
                                            }
                                        }
                                    }
                                }
                                (false, true) => {
                                    for inserted in lines_after {
                                        match version_from_json_line(inserted.as_bstr(), location) {
                                            Ok(version) => {
                                                self.changes.push(if version.yanked {
                                                    Change::Yanked(version)
                                                } else {
                                                    Change::Added(version)
                                                });
                                            }
                                            Err(e) => {
                                                err = Some(e);
                                                break;
                                            }
                                        }
                                    }
                                }
                                (true, true) | (false, false) => {
                                    /* ignore modifications, shouldn't exist */
                                }
                            }
                        },
                    );
                    if let Some(err) = err {
                        return Err(err.into());
                    }
                }
            }
        }
        Ok(Default::default())
    }

    pub fn into_result(mut self) -> Result<Vec<Change>, Error> {
        match self.err {
            Some(err) => Err(err),
            None => {
                if !self.delete_version_ids.is_empty() {
                    let deleted_version_ids = &self.delete_version_ids;
                    self.changes.retain(|change| match change {
                        Change::Added(v) | Change::Yanked(v) => {
                            !deleted_version_ids.contains(&v.id())
                        }
                        Change::Deleted { .. } => true,
                    })
                }
                Ok(self.changes)
            }
        }
    }
}

fn version_from_json_line(line: &[u8], file_name: &BStr) -> Result<CrateVersion, Error> {
    serde_json::from_slice(line).map_err(|err| Error::VersionDecode {
        source: err,
        file_name: file_name.into(),
        line: line.into(),
    })
}
<commit_msg>fix most of the tests<commit_after>use crate::index::diff::Error;
use crate::{Change, CrateVersion};
use bstr::BStr;
use git_repository as git;
use std::collections::BTreeSet;
use std::ops::Range;

#[derive(Default)]
pub(crate) struct Delegate {
    changes: Vec<Change>,
    delete_version_ids: BTreeSet<u64>,
    err: Option<Error>,
}

impl Delegate {
    pub fn handle(
        &mut self,
        change: git::object::tree::diff::Change<'_, '_, '_>,
    ) -> Result<git::object::tree::diff::Action, Error> {
        use git::bstr::ByteSlice;
        use git::object::tree::diff::change::Event::*;
        use git::objs::tree::EntryMode::*;
        fn entry_data(
            entry: git::objs::tree::EntryMode,
            id: git::Id<'_>,
        ) -> Result<Option<git::Object<'_>>, Error> {
            matches!(entry, Blob | BlobExecutable)
                .then(|| id.object())
                .transpose()
                .map_err(Into::into)
        }
        if change.location.contains(&b'.') {
            return Ok(Default::default());
        }
        match change.event {
            Addition { entry_mode, id } => {
                if let Some(obj) = entry_data(entry_mode, id)? {
                    for line in (&obj.data).lines() {
                        let version = version_from_json_line(line, change.location)?;
                        self.changes.push(if version.yanked {
                            Change::Yanked(version)
                        } else {
                            Change::Added(version)
                        });
                    }
                }
            }
            Deletion { entry_mode, .. } => {
                if entry_mode.is_no_tree() {
                    self.changes.push(Change::Deleted {
                        name: change.location.to_string(),
                    });
                }
            }
            Modification { .. } => {
                if let Some(diff) = change.event.diff().transpose()? {
                    let location = change.location;

                    let input = diff.line_tokens();
                    let mut err = None;
                    git::diff::blob::diff(
                        diff.algo,
                        &input,
                        |before: Range<u32>, after: Range<u32>| {
                            if err.is_some() {
                                return;
                            }
                            let mut lines_before = input.before
                                [before.start as usize..before.end as usize]
                                .iter()
                                .map(|&line| input.interner[line])
                                .peekable();
                            let mut lines_after = input.after
                                [after.start as usize..after.end as usize]
                                .iter()
                                .map(|&line| input.interner[line])
                                .peekable();
                            match (lines_before.peek().is_some(), lines_after.peek().is_some()) {
                                (true, false) => {
                                    for removed in lines_before {
                                        match version_from_json_line(removed.as_bstr(), location) {
                                            Ok(version) => {
                                                self.delete_version_ids.insert(version.id());
                                            }
                                            Err(e) => {
                                                err = Some(e);
                                                break;
                                            }
                                        }
                                    }
                                }
                                (false, true) => {
                                    for inserted in lines_after {
                                        match version_from_json_line(inserted.as_bstr(), location) {
                                            Ok(version) => {
                                                self.changes.push(if version.yanked {
                                                    Change::Yanked(version)
                                                } else {
                                                    Change::Added(version)
                                                });
                                            }
                                            Err(e) => {
                                                err = Some(e);
                                                break;
                                            }
                                        }
                                    }
                                }
                                (true, true) | (false, false) => {
                                    /* ignore modifications, shouldn't exist */
                                }
                            }
                        },
                    );
                    if let Some(err) = err {
                        return Err(err.into());
                    }
                }
            }
        }
        Ok(Default::default())
    }

    pub fn into_result(mut self) -> Result<Vec<Change>, Error> {
        match self.err {
            Some(err) => Err(err),
            None => {
                if !self.delete_version_ids.is_empty() {
                    let deleted_version_ids = &self.delete_version_ids;
                    self.changes.retain(|change| match change {
                        Change::Added(v) | Change::Yanked(v) => {
                            !deleted_version_ids.contains(&v.id())
                        }
                        Change::Deleted { .. } => true,
                    })
                }
                Ok(self.changes)
            }
        }
    }
}

fn version_from_json_line(line: &[u8], file_name: &BStr) -> Result<CrateVersion, Error> {
    serde_json::from_slice(line).map_err(|err| Error::VersionDecode {
        source: err,
        file_name: file_name.into(),
        line: line.into(),
    })
}
<|endoftext|>


<commit_before>use crate::clock::now;
use crate::timer::Inner;
use crate::{Delay, Error, /*Interval,*/ Timeout};
use std::cell::RefCell;
use std::fmt;
use std::sync::{Arc, Weak};
use std::time::Instant;

/// Handle to timer instance.
///
/// The `Handle` allows creating `Delay` instances that are driven by the
/// associated timer.
///
/// A `Handle` is obtained by calling [`Timer::handle`], [`Handle::current`], or
/// [`Handle::default`].
///
/// * [`Timer::handle`]: returns a handle associated with the specific timer.
///   The handle will always reference the same timer.
///
/// * [`Handle::current`]: returns a handle to the timer for the execution
///   context **at the time the function is called**. This function must be
///   called from a runtime that has an associated timer or it will panic.
///   The handle will always reference the same timer.
///
/// * [`Handle::default`]: returns a handle to the timer for the execution
///   context **at the time the handle is used**. This function is safe to call
///   at any time. The handle may reference different specific timer instances.
///   Calling `Handle::default().delay(...)` is always equivalent to
///   `Delay::new(...)`.
///
/// [`Timer::handle`]: struct.Timer.html#method.handle
/// [`Handle::current`]: #method.current
/// [`Handle::default`]: #method.default
#[derive(Debug, Clone)]
pub struct Handle {
    inner: Option<HandlePriv>,
}

/// Like `Handle` but never `None`.
#[derive(Clone)]
pub(crate) struct HandlePriv {
    inner: Weak<Inner>,
}

thread_local! {
    /// Tracks the timer for the current execution context.
    static CURRENT_TIMER: RefCell<Option<HandlePriv>> = RefCell::new(None)
}

/// Set the default timer for the duration of the closure.
///
/// From within the closure, [`Delay`] instances that are created via
/// [`Delay::new`] can be used.
///
/// # Panics
///
/// This function panics if there already is a default timer set.
///
/// [`Delay`]: ../struct.Delay.html
/// [`Delay::new`]: ../struct.Delay.html#method.new
pub fn with_default<F, R>(handle: &Handle, f: F) -> R
where
    F: FnOnce() -> R,
{
    // Ensure that the timer is removed from the thread-local context
    // when leaving the scope. This handles cases that involve panicking.
    struct Reset;

    impl Drop for Reset {
        fn drop(&mut self) {
            CURRENT_TIMER.with(|current| {
                let mut current = current.borrow_mut();
                *current = None;
            });
        }
    }

    // This ensures the value for the current timer gets reset even if there is
    // a panic.
    let _r = Reset;

    CURRENT_TIMER.with(|current| {
        {
            let mut current = current.borrow_mut();

            assert!(
                current.is_none(),
                "default Tokio timer already set \
                 for execution context"
            );

            let handle = handle
                .as_priv()
                .unwrap_or_else(|| panic!("`handle` does not reference a timer"));

            *current = Some(handle.clone());
        }

        f()
    })
}

impl Handle {
    pub(crate) fn new(inner: Weak<Inner>) -> Handle {
        let inner = HandlePriv { inner };
        Handle { inner: Some(inner) }
    }

    /// Returns a handle to the current timer.
    ///
    /// The current timer is the timer that is currently set as default using
    /// [`with_default`].
    ///
    /// This function should only be called from within the context of
    /// [`with_default`]. Calling this function from outside of this context
    /// will return a `Handle` that does not reference a timer. `Delay`
    /// instances created with this handle will error.
    ///
    /// See [type] level documentation for more ways to obtain a `Handle` value.
    ///
    /// [`with_default`]: ../fn.with_default.html
    /// [type]: #
    pub fn current() -> Handle {
        let private =
            HandlePriv::try_current().unwrap_or_else(|_| HandlePriv { inner: Weak::new() });

        Handle {
            inner: Some(private),
        }
    }

    /// Create a `Delay` driven by this handle's associated `Timer`.
    pub fn delay(&self, deadline: Instant) -> Delay {
        self.delay_timeout(deadline, Duration::from_secs(0))
    }

    fn delay_timeout(&self, deadline: Instant, duration: Duration) -> Delay {
        match self.inner {
            Some(ref handle_priv) => {
                Delay::new_with_handle(deadline, Duration::from_secs(0), handle_priv.clone())
            }
            None => Delay::new_timeout(deadline, duration),
        }
    }

    /// Create a `Timeout` driven by this handle's associated `Timer`.
    pub fn timeout<T>(&self, value: T, timeout: Duration) -> Timeout<T> {
        Timeout::new_with_delay(value, self.delay_timeout(now() + timeout, timeout))
    }

    /*
    /// Create a new `Interval` that starts at `at` and yields every `duration`
    /// interval after that.
    pub fn interval(&self, at: Instant, duration: Duration) -> Interval {
        Interval::new_with_delay(self.delay(at), duration)
    }
    */

    fn as_priv(&self) -> Option<&HandlePriv> {
        self.inner.as_ref()
    }
}

impl Default for Handle {
    fn default() -> Handle {
        Handle { inner: None }
    }
}

impl HandlePriv {
    /// Try to get a handle to the current timer.
    ///
    /// Returns `Err` if no handle is found.
    pub(crate) fn try_current() -> Result<HandlePriv, Error> {
        CURRENT_TIMER.with(|current| match *current.borrow() {
            Some(ref handle) => Ok(handle.clone()),
            None => Err(Error::shutdown()),
        })
    }

    /// Try to return a strong ref to the inner
    pub(crate) fn inner(&self) -> Option<Arc<Inner>> {
        self.inner.upgrade()
    }

    /// Consume the handle, returning the weak Inner ref.
    pub(crate) fn into_inner(self) -> Weak<Inner> {
        self.inner
    }
}

impl fmt::Debug for HandlePriv {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "HandlePriv")
    }
}
<commit_msg>timer: fix build (#1275)<commit_after>use crate::clock::now;
use crate::timer::Inner;
use crate::{Delay, Error, /*Interval,*/ Timeout};
use std::cell::RefCell;
use std::fmt;
use std::sync::{Arc, Weak};
use std::time::{Duration, Instant};

/// Handle to timer instance.
///
/// The `Handle` allows creating `Delay` instances that are driven by the
/// associated timer.
///
/// A `Handle` is obtained by calling [`Timer::handle`], [`Handle::current`], or
/// [`Handle::default`].
///
/// * [`Timer::handle`]: returns a handle associated with the specific timer.
///   The handle will always reference the same timer.
///
/// * [`Handle::current`]: returns a handle to the timer for the execution
///   context **at the time the function is called**. This function must be
///   called from a runtime that has an associated timer or it will panic.
///   The handle will always reference the same timer.
///
/// * [`Handle::default`]: returns a handle to the timer for the execution
///   context **at the time the handle is used**. This function is safe to call
///   at any time. The handle may reference different specific timer instances.
///   Calling `Handle::default().delay(...)` is always equivalent to
///   `Delay::new(...)`.
///
/// [`Timer::handle`]: struct.Timer.html#method.handle
/// [`Handle::current`]: #method.current
/// [`Handle::default`]: #method.default
#[derive(Debug, Clone)]
pub struct Handle {
    inner: Option<HandlePriv>,
}

/// Like `Handle` but never `None`.
#[derive(Clone)]
pub(crate) struct HandlePriv {
    inner: Weak<Inner>,
}

thread_local! {
    /// Tracks the timer for the current execution context.
    static CURRENT_TIMER: RefCell<Option<HandlePriv>> = RefCell::new(None)
}

/// Set the default timer for the duration of the closure.
///
/// From within the closure, [`Delay`] instances that are created via
/// [`Delay::new`] can be used.
///
/// # Panics
///
/// This function panics if there already is a default timer set.
///
/// [`Delay`]: ../struct.Delay.html
/// [`Delay::new`]: ../struct.Delay.html#method.new
pub fn with_default<F, R>(handle: &Handle, f: F) -> R
where
    F: FnOnce() -> R,
{
    // Ensure that the timer is removed from the thread-local context
    // when leaving the scope. This handles cases that involve panicking.
    struct Reset;

    impl Drop for Reset {
        fn drop(&mut self) {
            CURRENT_TIMER.with(|current| {
                let mut current = current.borrow_mut();
                *current = None;
            });
        }
    }

    // This ensures the value for the current timer gets reset even if there is
    // a panic.
    let _r = Reset;

    CURRENT_TIMER.with(|current| {
        {
            let mut current = current.borrow_mut();

            assert!(
                current.is_none(),
                "default Tokio timer already set \
                 for execution context"
            );

            let handle = handle
                .as_priv()
                .unwrap_or_else(|| panic!("`handle` does not reference a timer"));

            *current = Some(handle.clone());
        }

        f()
    })
}

impl Handle {
    pub(crate) fn new(inner: Weak<Inner>) -> Handle {
        let inner = HandlePriv { inner };
        Handle { inner: Some(inner) }
    }

    /// Returns a handle to the current timer.
    ///
    /// The current timer is the timer that is currently set as default using
    /// [`with_default`].
    ///
    /// This function should only be called from within the context of
    /// [`with_default`]. Calling this function from outside of this context
    /// will return a `Handle` that does not reference a timer. `Delay`
    /// instances created with this handle will error.
    ///
    /// See [type] level documentation for more ways to obtain a `Handle` value.
    ///
    /// [`with_default`]: ../fn.with_default.html
    /// [type]: #
    pub fn current() -> Handle {
        let private =
            HandlePriv::try_current().unwrap_or_else(|_| HandlePriv { inner: Weak::new() });

        Handle {
            inner: Some(private),
        }
    }

    /// Create a `Delay` driven by this handle's associated `Timer`.
    pub fn delay(&self, deadline: Instant) -> Delay {
        self.delay_timeout(deadline, Duration::from_secs(0))
    }

    fn delay_timeout(&self, deadline: Instant, duration: Duration) -> Delay {
        match self.inner {
            Some(ref handle_priv) => {
                Delay::new_with_handle(deadline, Duration::from_secs(0), handle_priv.clone())
            }
            None => Delay::new_timeout(deadline, duration),
        }
    }

    /// Create a `Timeout` driven by this handle's associated `Timer`.
    pub fn timeout<T>(&self, value: T, timeout: Duration) -> Timeout<T> {
        Timeout::new_with_delay(value, self.delay_timeout(now() + timeout, timeout))
    }

    /*
    /// Create a new `Interval` that starts at `at` and yields every `duration`
    /// interval after that.
    pub fn interval(&self, at: Instant, duration: Duration) -> Interval {
        Interval::new_with_delay(self.delay(at), duration)
    }
    */

    fn as_priv(&self) -> Option<&HandlePriv> {
        self.inner.as_ref()
    }
}

impl Default for Handle {
    fn default() -> Handle {
        Handle { inner: None }
    }
}

impl HandlePriv {
    /// Try to get a handle to the current timer.
    ///
    /// Returns `Err` if no handle is found.
    pub(crate) fn try_current() -> Result<HandlePriv, Error> {
        CURRENT_TIMER.with(|current| match *current.borrow() {
            Some(ref handle) => Ok(handle.clone()),
            None => Err(Error::shutdown()),
        })
    }

    /// Try to return a strong ref to the inner
    pub(crate) fn inner(&self) -> Option<Arc<Inner>> {
        self.inner.upgrade()
    }

    /// Consume the handle, returning the weak Inner ref.
    pub(crate) fn into_inner(self) -> Weak<Inner> {
        self.inner
    }
}

impl fmt::Debug for HandlePriv {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "HandlePriv")
    }
}
<|endoftext|>


<commit_before>extern crate syscall;

use std::{io, mem, slice};
use std::os::unix::io::RawFd;

use syscall::SigAction;

pub const PATH_SEPARATOR: &str = ";";

pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub const SIGHUP: i32 = syscall::SIGHUP as i32;
pub const SIGINT: i32 = syscall::SIGINT as i32;
pub const SIGTERM: i32 = syscall::SIGTERM as i32;
pub const SIGCONT: i32 = syscall::SIGCONT as i32;
pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;

pub const STDIN_FILENO: RawFd = 0;
pub const STDOUT_FILENO: RawFd = 1;
pub const STDERR_FILENO: RawFd = 2;

pub unsafe fn fork() -> io::Result<u32> {
    cvt(syscall::clone(0)).map(|pid| pid as u32)
}

pub fn getpid() -> io::Result<u32> {
    cvt(syscall::getpid()).map(|pid| pid as u32)
}

pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask: [0; 2],
        sa_flags: 0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub fn dup(fd: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup(fd, &[]))
}

pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup2(old, new, &[]))
}

pub fn close(fd: RawFd) -> io::Result<()> {
    cvt(syscall::close(fd)).and(Ok(()))
}

pub fn isatty(fd: RawFd) -> bool {
    if let Ok(fd) = syscall::dup(f, &[]) {
        let _ = syscall::close(fd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be controlled
    /// by the shell.
    pub fn unblock() {}
}

pub mod job_control {
    use shell::job_control::*;

    use std::io::{self, Write};
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall;
    use shell::foreground::ForegroundSignals;
    use shell::status::TERMINATED;
    use shell::Shell;

    pub fn watch_background(
        fg: Arc<ForegroundSignals>,
        processes: Arc<Mutex<Vec<BackgroundProcess>>>,
        pid: u32,
        njob: usize,
    ) {
        // TODO: Implement this using syscall::call::waitpid
    }

    pub fn watch_foreground<'a, F, D>(
        _shell: &mut Shell<'a>,
        pid: u32,
        _last_pid: u32,
        _get_command: F,
        mut drop_command: D,
    ) -> i32
    where
        F: FnOnce() -> String,
        D: FnMut(i32),
    {
        loop {
            let mut status_raw = 0;
            match syscall::waitpid(pid as usize, &mut status_raw, 0) {
                Ok(0) => (),
                Ok(_pid) => {
                    let status = ExitStatus::from_raw(status_raw as i32);
                    if let Some(code) = status.code() {
                        break code;
                    } else {
                        let stderr = io::stderr();
                        let mut stderr = stderr.lock();
                        let _ = stderr.write_all(b"ion: child ended by signal\n");
                        break TERMINATED;
                    }
                }
                Err(err) => {
                    let stderr = io::stderr();
                    let mut stderr = stderr.lock();
                    let _ = writeln!(stderr, "ion: failed to wait: {}", err);
                    break 100; // TODO what should we return here?
                }
            }
        }
    }
}

pub mod variables {
    pub fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }
}
<commit_msg>Fix typo in Redox submodule, fix istty check<commit_after>extern crate syscall;

use std::{io, mem, slice};
use std::os::unix::io::RawFd;

use syscall::SigAction;

pub const PATH_SEPARATOR: &str = ";";

pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub const SIGHUP: i32 = syscall::SIGHUP as i32;
pub const SIGINT: i32 = syscall::SIGINT as i32;
pub const SIGTERM: i32 = syscall::SIGTERM as i32;
pub const SIGCONT: i32 = syscall::SIGCONT as i32;
pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;

pub const STDIN_FILENO: RawFd = 0;
pub const STDOUT_FILENO: RawFd = 1;
pub const STDERR_FILENO: RawFd = 2;

pub unsafe fn fork() -> io::Result<u32> {
    cvt(syscall::clone(0)).map(|pid| pid as u32)
}

pub fn getpid() -> io::Result<u32> {
    cvt(syscall::getpid()).map(|pid| pid as u32)
}

pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask: [0; 2],
        sa_flags: 0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub fn dup(fd: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup(fd, &[]))
}

pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
    cvt(syscall::dup2(old, new, &[]))
}

pub fn close(fd: RawFd) -> io::Result<()> {
    cvt(syscall::close(fd)).and(Ok(()))
}

pub fn isatty(fd: RawFd) -> bool {
    if let Ok(tfd) = syscall::dup(fd, b"termios") {
        let _ = syscall::close(tfd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be controlled
    /// by the shell.
    pub fn unblock() {}
}

pub mod job_control {
    use shell::job_control::*;

    use std::io::{self, Write};
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall;
    use shell::foreground::ForegroundSignals;
    use shell::status::TERMINATED;
    use shell::Shell;

    pub fn watch_background(
        fg: Arc<ForegroundSignals>,
        processes: Arc<Mutex<Vec<BackgroundProcess>>>,
        pid: u32,
        njob: usize,
    ) {
        // TODO: Implement this using syscall::call::waitpid
    }

    pub fn watch_foreground<'a, F, D>(
        _shell: &mut Shell<'a>,
        pid: u32,
        _last_pid: u32,
        _get_command: F,
        mut drop_command: D,
    ) -> i32
    where
        F: FnOnce() -> String,
        D: FnMut(i32),
    {
        loop {
            let mut status_raw = 0;
            match syscall::waitpid(pid as usize, &mut status_raw, 0) {
                Ok(0) => (),
                Ok(_pid) => {
                    let status = ExitStatus::from_raw(status_raw as i32);
                    if let Some(code) = status.code() {
                        break code;
                    } else {
                        let stderr = io::stderr();
                        let mut stderr = stderr.lock();
                        let _ = stderr.write_all(b"ion: child ended by signal\n");
                        break TERMINATED;
                    }
                }
                Err(err) => {
                    let stderr = io::stderr();
                    let mut stderr = stderr.lock();
                    let _ = writeln!(stderr, "ion: failed to wait: {}", err);
                    break 100; // TODO what should we return here?
                }
            }
        }
    }
}

pub mod variables {
    pub fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }
}
<|endoftext|>


<commit_before><commit_msg>declare foreign function signatures<commit_after>use libc::{c_int, c_char, c_long, time_t, size_t};
use super::data_structs::*;

#[link(name = "jalali", kind = "static")]
extern {
  // jalali.h
  fn jalali_is_jleap(year: c_int) -> c_int;
  fn jalali_create_time_from_secs(time: time_t, ab_jtm: *mut AB_JTM);
  fn jalali_create_secs_from_time(ab_jtm: *const AB_JTM) -> time_t;
  fn jalali_create_date_from_days(j: *mut JTM) -> c_int;
  fn jalali_create_days_from_date(j: *mut JTM) -> c_int;
  fn jalali_get_jyear_info(year_info: *mut JYInfo);
  fn jalali_get_date(p: c_int, jtm: *mut JTM);
  fn jalali_get_diff(jtm: *const JTM) -> c_int;
  fn jalali_update(jtm: *mut JTM);
  fn jalali_show_time(jtm: *const JTM);
  fn jalali_year_month_days(year: c_int, month: c_int) -> c_int;

  // jtime.h
  fn jasctime(jtm: *const JTM) -> *mut c_char;
  fn jctime(timep: *const time_t) -> *mut c_char;
  fn jgmtime(timep: *const time_t) -> *mut JTM;
  fn jlocaltime(timep: *const time_t) -> &mut JTM;
  fn jmktime(jtm: *mut JTM) -> time_t;
  fn jstrftime(s: *mut c_char, max: size_t,format: *const c_char, jtm: *const JTM) -> size_t;
  fn jstrptime(s: *const c_char, format: *const c_char, jtm: *mut JTM) -> *mut c_char;
  fn jasctime_r(jtm: *const JTM, buf: *mut c_char) -> *mut c_char;
  fn jctime_r(timep: *const time_t, buf: *mut c_char) -> *mut c_char;
  fn jgmtime_r(timep: *const time_t, result: *mut JTM) -> *mut JTM;
  fn jlocaltime_r(timep: *const time_t, result: *mut JTM) -> *mut JTM;
  fn jalali_to_farsi(buf: *mut c_char, n: size_t, padding: c_int, pad: *mut c_char, d: c_int) -> c_int;
}
<|endoftext|>