<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction%20strategies) of
/// β-reductions. `Applicative` order will not fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator. The default is `Normal`.
pub const EVALUATION_ORDER: Order = Normal;

/// The available variants of β-reduction evaluation order.
#[derive(Debug, PartialEq)]
pub enum Order {
    Normal,
    Applicative
}

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        match EVALUATION_ORDER {
            Normal => self._beta_once_normal(0),
            Applicative => self._beta_once_applicative(0)
        };
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    true
                } else {
                    if !self.lhs_ref_mut().unwrap()._beta_once_normal(depth) {
                        self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                    } else {
                        true
                    }
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if !self.lhs_ref().unwrap().is_beta_reducible() &&
                   !self.rhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    true
                } else {
                    if !self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) {
                        self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                    } else {
                        true
                    }
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible());
    /// assert!(!not_reducible.is_beta_reducible());
    /// ```
    pub fn is_beta_reducible(&self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref().unwrap().is_beta_reducible(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible() ||
                    self.rhs_ref().unwrap().is_beta_reducible()
                }
            }
        }
    }

    /// Performs full β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

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

    #[test]
    fn evaluation_order() {
        match EVALUATION_ORDER {
            Normal => {
                let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_full(should_reduce), Var(1))
            },
            Applicative => {
                let shouldnt_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_once(shouldnt_reduce), parse(&"(λ2)((λ111)(λ111)(λ111))").unwrap())
            }
        }
    }
}
<commit_msg>fix link<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` order will not fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator. The default is `Normal`.
pub const EVALUATION_ORDER: Order = Normal;

/// The available variants of β-reduction evaluation order.
#[derive(Debug, PartialEq)]
pub enum Order {
    Normal,
    Applicative
}

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        match EVALUATION_ORDER {
            Normal => self._beta_once_normal(0),
            Applicative => self._beta_once_applicative(0)
        };
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    true
                } else {
                    if !self.lhs_ref_mut().unwrap()._beta_once_normal(depth) {
                        self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                    } else {
                        true
                    }
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if !self.lhs_ref().unwrap().is_beta_reducible() &&
                   !self.rhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    true
                } else {
                    if !self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) {
                        self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                    } else {
                        true
                    }
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible());
    /// assert!(!not_reducible.is_beta_reducible());
    /// ```
    pub fn is_beta_reducible(&self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref().unwrap().is_beta_reducible(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible() ||
                    self.rhs_ref().unwrap().is_beta_reducible()
                }
            }
        }
    }

    /// Performs full β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

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

    #[test]
    fn evaluation_order() {
        match EVALUATION_ORDER {
            Normal => {
                let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_full(should_reduce), Var(1))
            },
            Applicative => {
                let shouldnt_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_once(shouldnt_reduce), parse(&"(λ2)((λ111)(λ111)(λ111))").unwrap())
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;

#[no_mangle]
pub extern "C" fn filesrc_new() -> *mut FileSrc {
    let mut instance = Box::new(FileSrc::new());
    return &mut *instance;
}

#[no_mangle]
pub extern "C" fn filesrc_drop(ptr: *mut FileSrc) {
    let filesrc: &mut FileSrc = unsafe { &mut *ptr };

    println!("drop");
    drop(filesrc);
}

#[no_mangle]
pub extern "C" fn filesrc_fill(ptr: *mut FileSrc) {
    let filesrc: &mut FileSrc = unsafe { &mut *ptr };

    println!("fill");
    filesrc.location = Some(String::from("bla"));
}

#[derive(Debug)]
pub struct FileSrc {
    location: Option<String>,
}

impl FileSrc {
    fn new() -> FileSrc {
        FileSrc { location: None }
    }
}

impl Drop for FileSrc {
    fn drop(&mut self) {
        println!("drop");
    }
}
<commit_msg>Use Box::from/into_raw()<commit_after>#[no_mangle]
pub extern "C" fn filesrc_new() -> *mut FileSrc {
    let instance = Box::new(FileSrc::new());
    return Box::into_raw(instance);
}

#[no_mangle]
pub extern "C" fn filesrc_drop(ptr: *mut FileSrc) {
    unsafe { Box::from_raw(ptr) };
}

#[no_mangle]
pub extern "C" fn filesrc_fill(ptr: *mut FileSrc) {
    let filesrc: &mut FileSrc = unsafe { &mut *ptr };

    println!("fill");
    filesrc.location = Some(String::from("bla"));
}

#[derive(Debug)]
pub struct FileSrc {
    location: Option<String>,
}

impl FileSrc {
    fn new() -> FileSrc {
        FileSrc { location: None }
    }
}

impl Drop for FileSrc {
    fn drop(&mut self) {
        println!("drop");
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::str::FromStr;

// get from parent
use ERes;
use err;
use read_file;

#[derive(Debug)]
pub struct Schematic {
    libraries:Vec<String>,
    description:Description,
    components:Vec<Component>,
}

impl Schematic {
    fn new() -> Schematic {
        Schematic {
            libraries:vec![],
            description:Description::new(),
            components:vec![],
        }
    }

    fn add_library(&mut self, s:&str) {
        self.libraries.push(String::from(s))
    }

    fn set_description(&mut self, d:&Description) {
        self.description.clone_from(d)
    }

    fn append_component(&mut self, c:Component) {
        self.components.push(c)
    }
}

impl fmt::Display for Schematic {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema Schematic File Version 2"));
        for v in &self.libraries[..] {
            try!(writeln!(f, "LIBS:{}", v))
        }
        try!(write!(f, "{}", self.description));
        for v in &self.components[..] {
            try!(write!(f, "{}", v))
        }
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        return (self.v[self.i]).clone()
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}
/*
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title "Normal"
Date "Tue 19 May 2015"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDesc
*/
#[derive(Debug,Clone)]
pub struct Description {
    size:String,
    dimx:i64,
    dimy:i64,
    title:String,
    date:String,
    rev:String,
    comp:String,
    comment1:String,
    comment2:String,
    comment3:String,
    comment4:String,
}

impl Description {
    fn new() -> Description {
        Description {
            size:String::from(""),
            dimx:0,
            dimy:0,
            title:String::from("Normal"),
            date:String::from("Tue 19 May 2015"),
            rev:String::from(""),
            comp:String::from(""),
            comment1:String::from(""),
            comment2:String::from(""),
            comment3:String::from(""),
            comment4:String::from(""),
        }
    }
    fn set_size(&mut self, s:&String) {
        self.size.clone_from(s)
    }
    fn set_dimx(&mut self, i:i64) {
        self.dimx = i;
    }
    fn set_dimy(&mut self, i:i64) {
        self.dimy = i;
    }
    fn set_title(&mut self, s:&String) {
        self.title.clone_from(s)
    }
    fn set_date(&mut self, s:&String) {
        self.date.clone_from(s)
    }
    fn set_rev(&mut self, s:&String) {
        self.rev.clone_from(s)
    }
    fn set_comp(&mut self, s:&String) {
        self.comp.clone_from(s)
    }
    fn set_comment1(&mut self, s:&String) {
        self.comment1.clone_from(s)
    }
    fn set_comment2(&mut self, s:&String) {
        self.comment2.clone_from(s)
    }
    fn set_comment3(&mut self, s:&String) {
        self.comment3.clone_from(s)
    }
    fn set_comment4(&mut self, s:&String) {
        self.comment4.clone_from(s)
    }
}

impl fmt::Display for Description {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Descr {} {} {}", self.size, self.dimx, self.dimy));
        try!(writeln!(f, "encoding utf-8"));
        try!(writeln!(f, "Sheet 1 1")); // TODO: handle sheet
        try!(writeln!(f, "Title \"{}\"", self.title));
        try!(writeln!(f, "Date \"{}\"", self.date));
        try!(writeln!(f, "Rev \"{}\"", self.rev));
        try!(writeln!(f, "Comp \"{}\"", self.comp));
        try!(writeln!(f, "Comment1 \"{}\"", self.comment1));
        try!(writeln!(f, "Comment2 \"{}\"", self.comment2));
        try!(writeln!(f, "Comment3 \"{}\"", self.comment3));
        try!(writeln!(f, "Comment4 \"{}\"", self.comment4));
        writeln!(f, "$EndDescr")
    }
}

#[derive(Debug)]
struct Component {
    name:String,
    reference:String,
}

impl Component {
    fn new() -> Component {
        Component {
            name:String::from("EFM32HG310"),
            reference:String::from("U1"),
        }
    }
}

impl fmt::Display for Component {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Comp"));
        try!(writeln!(f, "L {} {}", self.name, self.reference));
        writeln!(f, "$EndComp")
    }
}

fn assume_string(e:&'static str, s:&String) -> ERes<()> {
    if String::from(e) != *s {
        return Err(format!("expecting: {}, actually: {}", e, s))
    }
    return Ok(())
}

fn parse_split_n(n:usize, s:&String) -> ERes<Vec<String>> {
    let sp:Vec<&str> = s.splitn(n, ' ').collect();
    if sp.len() < n {
        return Err(format!("expecting {} elements in {}", n, s))
    }
    return Ok(sp.iter().map(|x| String::from(*x)).collect())
}

fn i64_from_string(s:&String) -> ERes<i64> {
    match i64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("int parse error in {}", s))
    }
}

// this is not perfect
fn unquote_string(s:&String) -> ERes<String> {
    let l = s.len();
    if s.starts_with("\"") && s.ends_with("\"") {
        let mut s = s.clone();
        s.remove(l-1);
        s.remove(0);
        return Ok(s)
    }
    Err(format!("expecting quoted string: {}", s))
}

fn word_and_qstring<F>(d:&mut Description, name:&'static str, s:&String, setter:F) -> ERes<()>
    where F:Fn(&mut Description, &String) -> ()
{
    let v = try!(parse_split_n(2, s));
    try!(assume_string(name, &v[0]));
    setter(d, &try!(unquote_string(&v[1])));
    Ok(())
}

fn parse_description(p:&mut ParseState) -> ERes<Description> {
    let mut d = Description::new();
    let v = try!(parse_split_n(4, &p.here()));
    d.set_size(&v[1]);
    d.set_dimx(try!(i64_from_string(&v[2])));
    d.set_dimy(try!(i64_from_string(&v[3])));
    p.next(); // $Descr
    p.next(); // encoding
    try!(assume_string("Sheet 1 1", &p.here())); // TODO
    p.next(); // Sheet
    try!(word_and_qstring(&mut d, "Title", &p.here(), |d, x| d.set_title(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Date", &p.here(), |d, x| d.set_date(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Rev", &p.here(), |d, x| d.set_rev(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comp", &p.here(), |d, x| d.set_comp(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment1", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment2", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment3", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment4", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(assume_string("$EndDescr", &p.here()));
    Ok(d)
}

fn parse_component(p:&mut ParseState) -> ERes<Component> {
    let mut d = Component::new();
    Ok(d)
}

fn parse(s: &str) -> ERes<Schematic> {
    let mut sch = Schematic::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema Schematic File Version 2");
    while !p.eof() {
        {
          let s = p.here();
          if !s.starts_with("LIBS:") {
              break
          }
            sch.add_library(&s[5..]);
        }
        p.next();
    }
    assume_line!(p, "EELAYER 25 0");
    assume_line!(p, "EELAYER END");
    while !p.eof() {
        {
            match p.here().split_whitespace().next() {
                Some("$Descr") => {
                    let d = try!(parse_description(p));
                    sch.set_description(&d)
                },
                Some("$Comp") => {
                    let d = try!(parse_component(p));
                    sch.append_component(d)
                },
                Some(x) => {
                    //println!("TODO other parts: {}", x);
                },
                None => unreachable!()
            }
        }
        p.next()
    }
    Ok(sch)
}

pub fn parse_str(s: &str) -> Schematic {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Schematic {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>component field parsing WIP<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::str::FromStr;

// get from parent
use ERes;
use err;
use read_file;

#[derive(Debug)]
pub struct Schematic {
    libraries:Vec<String>,
    description:Description,
    components:Vec<Component>,
}

impl Schematic {
    fn new() -> Schematic {
        Schematic {
            libraries:vec![],
            description:Description::new(),
            components:vec![],
        }
    }

    fn add_library(&mut self, s:&str) {
        self.libraries.push(String::from(s))
    }

    fn set_description(&mut self, d:&Description) {
        self.description.clone_from(d)
    }

    fn append_component(&mut self, c:Component) {
        self.components.push(c)
    }
}

impl fmt::Display for Schematic {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema Schematic File Version 2"));
        for v in &self.libraries[..] {
            try!(writeln!(f, "LIBS:{}", v))
        }
        try!(write!(f, "{}", self.description));
        for v in &self.components[..] {
            try!(write!(f, "{}", v))
        }
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        return (self.v[self.i]).clone()
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}
/*
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title "Normal"
Date "Tue 19 May 2015"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDesc
*/
#[derive(Debug,Clone)]
pub struct Description {
    size:String,
    dimx:i64,
    dimy:i64,
    title:String,
    date:String,
    rev:String,
    comp:String,
    comment1:String,
    comment2:String,
    comment3:String,
    comment4:String,
}

impl Description {
    fn new() -> Description {
        Description {
            size:String::from(""),
            dimx:0,
            dimy:0,
            title:String::from("Normal"),
            date:String::from("Tue 19 May 2015"),
            rev:String::from(""),
            comp:String::from(""),
            comment1:String::from(""),
            comment2:String::from(""),
            comment3:String::from(""),
            comment4:String::from(""),
        }
    }
    fn set_size(&mut self, s:&String) {
        self.size.clone_from(s)
    }
    fn set_dimx(&mut self, i:i64) {
        self.dimx = i;
    }
    fn set_dimy(&mut self, i:i64) {
        self.dimy = i;
    }
    fn set_title(&mut self, s:&String) {
        self.title.clone_from(s)
    }
    fn set_date(&mut self, s:&String) {
        self.date.clone_from(s)
    }
    fn set_rev(&mut self, s:&String) {
        self.rev.clone_from(s)
    }
    fn set_comp(&mut self, s:&String) {
        self.comp.clone_from(s)
    }
    fn set_comment1(&mut self, s:&String) {
        self.comment1.clone_from(s)
    }
    fn set_comment2(&mut self, s:&String) {
        self.comment2.clone_from(s)
    }
    fn set_comment3(&mut self, s:&String) {
        self.comment3.clone_from(s)
    }
    fn set_comment4(&mut self, s:&String) {
        self.comment4.clone_from(s)
    }
}

impl fmt::Display for Description {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Descr {} {} {}", self.size, self.dimx, self.dimy));
        try!(writeln!(f, "encoding utf-8"));
        try!(writeln!(f, "Sheet 1 1")); // TODO: handle sheet
        try!(writeln!(f, "Title \"{}\"", self.title));
        try!(writeln!(f, "Date \"{}\"", self.date));
        try!(writeln!(f, "Rev \"{}\"", self.rev));
        try!(writeln!(f, "Comp \"{}\"", self.comp));
        try!(writeln!(f, "Comment1 \"{}\"", self.comment1));
        try!(writeln!(f, "Comment2 \"{}\"", self.comment2));
        try!(writeln!(f, "Comment3 \"{}\"", self.comment3));
        try!(writeln!(f, "Comment4 \"{}\"", self.comment4));
        writeln!(f, "$EndDescr")
    }
}

#[derive(Debug)]
struct Component {
    name:String,
    reference:String,
    u:String, // TODO
    x:f64,
    y:f64,
    fields:Vec<ComponentField>,
}

impl Component {
    fn new() -> Component {
        Component {
            name:String::from("DUMMY"),
            reference:String::from("U1"),
            u:String::from(""),
            x:0.0,
            y:0.0,
            fields:vec![],
        }
    }

    fn set_name(&mut self, s:&String) {
        self.name.clone_from(s)
    }
    fn set_reference(&mut self, s:&String) {
        self.reference.clone_from(s)
    }
    fn set_u(&mut self, s:&String) {
        self.u.clone_from(s)
    }
    fn set_x(&mut self, x:f64) {
        self.x = x
    }
    fn set_y(&mut self, y:f64) {
        self.y = y
    }
    fn add_field(&mut self, f:ComponentField) {
        self.fields.push(f)
    }

}

impl fmt::Display for Component {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "$Comp"));
        try!(writeln!(f, "L {} {}", self.name, self.reference));
        try!(writeln!(f, "{}", self.u));
        try!(writeln!(f, "P {} {}", self.x, self.y));
        writeln!(f, "$EndComp")
    }
}

#[derive(Debug)]
enum Orientation {
    Horizontal,
    Vertical
}

impl Orientation {
    fn new(c:char) -> ERes<Orientation> {
        match c {
            'H' => Ok(Orientation::Horizontal),
            'V' => Ok(Orientation::Vertical),
            _ => Err(format!("unknown orientation {}", c))
        }

    }
}

#[derive(Debug)]
enum Justify {
    Left,
    Right,
    Center,
    Bottom,
    Top,
}

impl Justify {
    fn new(c: char) -> ERes<Justify> {
        match c {
            'C' => Ok(Justify::Center),
            'R' => Ok(Justify::Right),
            'L' => Ok(Justify::Left),
            'B' => Ok(Justify::Bottom),
            'T' => Ok(Justify::Top),
            _ => Err(format!("unexpected justify: {}", c))
        }
    }
}

#[derive(Debug)]
struct ComponentField {
    i:i64,
    value:String,
    orientation:Orientation,
    x:f64,
    y:f64,
    size:i64,
    visible:bool,
    hjustify:Justify,
    vjustify:Justify,
    italic:bool,
    bold:bool,
    name:Option<String>,
}

impl ComponentField {
    fn new(v:&Vec<String>) -> ERes<ComponentField> {
        if v.len() != 10 && v.len() != 11 {
            return Err(format!("expecting 10 or 11 parts got {}", v.len()))
        }
        let name = if v.len() == 11 {
            Some(try!(unquote_string(&v[10])))
        } else {
            None
        };
        let c = ComponentField {
            i:try!(i64_from_string(&v[1])),
            value:try!(unquote_string(&v[2])),
            orientation:try!(Orientation::new(char_at(&v[3],0))),
            x:try!(f64_from_string(&v[4])),
            y:try!(f64_from_string(&v[5])),
            size:try!(i64_from_string(&v[6])),
            visible:try!(bool_from_string(&v[7],"0000","0001")),
            hjustify:try!(Justify::new(char_at(&v[8], 0))),
            vjustify:try!(Justify::new(char_at(&v[9], 0))),
            italic:try!(bool_from(char_at(&v[9], 1), 'I', 'N')),
            bold:try!(bool_from(char_at(&v[9], 1), 'B', 'N')),
            name:name,
        };
        Ok(c)
    }
}

fn char_at(s:&String, p:usize) -> char {
    let v:Vec<char> = s.chars().collect();
    v[..][p]
}

fn assume_string(e:&'static str, s:&String) -> ERes<()> {
    if String::from(e) != *s {
        return Err(format!("expecting: {}, actually: {}", e, s))
    }
    return Ok(())
}

fn parse_split_n(n:usize, s:&String) -> ERes<Vec<String>> {
    let sp:Vec<&str> = s.splitn(n, ' ').collect();
    if sp.len() < n {
        return Err(format!("expecting {} elements in {}", n, s))
    }
    return Ok(sp.iter().map(|x| String::from(*x)).collect())
}

fn parse_split_quote_aware(s:&String) -> Vec<String> {
    let mut v:Vec<String> = vec![];
    let mut in_q:bool = false;
    let mut s2:String = String::from("");
    for c in s.chars() {
        if !in_q && c == '\"' {
            in_q = true;
            s2.push(c);
            continue
        }
        if in_q && c == '\"' {
            in_q = false;
            s2.push(c);
            continue
        }
        if c == ' ' {
            if s2.len() > 0 {
                v.push(s2.clone());
                s2.clear();
            }
            continue;
        }
        s2.push(c);
    }
    if s2.len() > 0 {
        v.push(s2.clone())
    }
    return v

}

fn i64_from_string(s:&String) -> ERes<i64> {
    match i64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("int parse error in {}", s))
    }
}

fn f64_from_string(s:&String) -> ERes<f64> {
    match f64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("float parse error in {}", s))
    }
}

fn bool_from_string(s:&String, t:&'static str, f:&'static str) -> ERes<bool> {
    if &s[..] == t {
        return Ok(true)
    }
    if &s[..] == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", s, t, f))
}

fn bool_from<T: PartialEq + fmt::Display>(i:T, t:T, f:T) -> ERes<bool> {
    if i == t {
        return Ok(true)
    }
    if i == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", i, t, f))
}

// this is not perfect
fn unquote_string(s:&String) -> ERes<String> {
    let l = s.len();
    if s.starts_with("\"") && s.ends_with("\"") {
        let mut s = s.clone();
        s.remove(l-1);
        s.remove(0);
        return Ok(s)
    }
    Err(format!("expecting quoted string: {}", s))
}

fn word_and_qstring<F>(d:&mut Description, name:&'static str, s:&String, setter:F) -> ERes<()>
    where F:Fn(&mut Description, &String) -> ()
{
    let v = try!(parse_split_n(2, s));
    try!(assume_string(name, &v[0]));
    setter(d, &try!(unquote_string(&v[1])));
    Ok(())
}

fn parse_description(p:&mut ParseState) -> ERes<Description> {
    let mut d = Description::new();
    let v = try!(parse_split_n(4, &p.here()));
    d.set_size(&v[1]);
    d.set_dimx(try!(i64_from_string(&v[2])));
    d.set_dimy(try!(i64_from_string(&v[3])));
    p.next(); // $Descr
    p.next(); // encoding
    try!(assume_string("Sheet 1 1", &p.here())); // TODO
    p.next(); // Sheet
    try!(word_and_qstring(&mut d, "Title", &p.here(), |d, x| d.set_title(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Date", &p.here(), |d, x| d.set_date(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Rev", &p.here(), |d, x| d.set_rev(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comp", &p.here(), |d, x| d.set_comp(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment1", &p.here(), |d, x| d.set_comment1(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment2", &p.here(), |d, x| d.set_comment2(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment3", &p.here(), |d, x| d.set_comment3(x)));
    p.next();
    try!(word_and_qstring(&mut d, "Comment4", &p.here(), |d, x| d.set_comment4(x)));
    p.next();
    try!(assume_string("$EndDescr", &p.here()));
    Ok(d)
}

fn parse_component_l(p:&mut ParseState, d:&mut Component) -> ERes<()> {
    let v = try!(parse_split_n(3, &p.here()));
    d.set_name(&v[1]);
    d.set_reference(&v[2]);
    Ok(())
}

fn parse_component_u(p:&mut ParseState, d:&mut Component) -> ERes<()> {
    d.set_u(&p.here());
    Ok(())
}

fn parse_component_p(p:&mut ParseState, d:&mut Component) -> ERes<()> {
    let v = try!(parse_split_n(3, &p.here()));
    d.set_x(try!(f64_from_string(&v[1])));
    d.set_y(try!(f64_from_string(&v[2])));
    Ok(())
}

fn parse_component_f(p:&mut ParseState, d:&mut Component) -> ERes<()> {
    //println!("{}", p.here());
    let v = parse_split_quote_aware(&p.here());
    let f = try!(ComponentField::new(&v));
    d.add_field(f);
    Ok(())
}

fn parse_component(p:&mut ParseState) -> ERes<Component> {
    let mut d = Component::new();
    p.next();
    loop {
        let s = p.here();
        if s == "$EndComp" {
            break;
        }
        match s.split_whitespace().next() {
            Some("L") => try!(parse_component_l(p, &mut d)),
            Some("U") => try!(parse_component_u(p, &mut d)),
            Some("P") => try!(parse_component_p(p, &mut d)),
            Some("F") => try!(parse_component_f(p, &mut d)),
            _ => println!("skipping unknown component line {}", s)
        }
        p.next()
    }
    Ok(d)
}

fn parse(s: &str) -> ERes<Schematic> {
    let mut sch = Schematic::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema Schematic File Version 2");
    while !p.eof() {
        {
          let s = p.here();
          if !s.starts_with("LIBS:") {
              break
          }
            sch.add_library(&s[5..]);
        }
        p.next();
    }
    assume_line!(p, "EELAYER 25 0");
    assume_line!(p, "EELAYER END");
    while !p.eof() {
        {
            match p.here().split_whitespace().next() {
                Some("$Descr") => {
                    let d = try!(parse_description(p));
                    sch.set_description(&d)
                },
                Some("$Comp") => {
                    let d = try!(parse_component(p));
                    sch.append_component(d)
                },
                Some(_) => {
                    //println!("TODO other parts: {}", x);
                },
                None => unreachable!()
            }
        }
        p.next()
    }
    Ok(sch)
}

pub fn parse_str(s: &str) -> Schematic {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Schematic {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;
use std::result;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::{Binding, UniqueBinding};
use js_types::allocator::Allocator;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    heap: Rc<RefCell<AllocBox>>,
    locals: HashMap<Binding, UniqueBinding>,
    stack: HashMap<UniqueBinding, JsVar>,
    maybe_globals: HashSet<Binding>,
    tag: ScopeTag,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ScopeTag {
    Call,
    Block,
}

#[derive(Copy, Clone, Debug)]
pub enum LookupError {
    Unreachable,
    FnBoundary,
    CheckParent,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(tag: ScopeTag, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            heap: heap.clone(),
            locals: HashMap::new(),
            stack: HashMap::new(),
            maybe_globals: HashSet::new(),
            tag: tag,
        }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.stack.len()
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        if self.locals.contains_key(&var.binding) {
            // If the variable we're trying to create was already allocated,
            // just update its value and mark it as non-global.
            self.maybe_globals.remove(&var.binding);
            return self.update_var(var, ptr);
        }
        // Maybe insert the variable's pointer data into the heap
        let res = match var.t {
            JsType::JsPtr(_) =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.heap.borrow_mut().alloc(var.unique.clone(), ptr)
                } else {
                    return Err(GcError::PtrAlloc);
                },
            _ => if let Some(_) = ptr { Err(GcError::PtrAlloc) } else { Ok(()) },
        };
        self.bind_var(var);
        res
    }

    /// Push an already-allocated JsVar onto the stack.
    pub fn bind_var(&mut self, var: JsVar) {
        // Create a mapping from the local binding to the unique binding
        self.locals.insert(var.binding.clone(), var.unique.clone());
        // Push the unique binding onto the stack
        self.stack.insert(var.unique.clone(), var);
    }

    fn rebind_var(&mut self, local: Binding, unique: UniqueBinding, var: JsVar) {
        self.locals.insert(local, unique.clone());
        self.stack.insert(unique, var);
    }

    pub fn mark_global(&mut self, binding: &Binding) {
        self.maybe_globals.insert(binding.clone());
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, local: &Binding) -> result::Result<(JsVar, Option<JsPtrEnum>), LookupError> {
        if let Some(unique) = self.locals.get(local) {
            if let Some(var) = self.stack.get(unique) {
                match var.t {
                    JsType::JsPtr(_) => {
                        if let Some(alloc) = self.heap.borrow().find_id(unique) {
                            Ok((var.clone(), Some(alloc.borrow().clone())))
                        } else {
                            // This case should be impossible unless you have an
                            // invalid ptr, which should also be impossible.
                            Err(LookupError::Unreachable)
                        }
                    },
                    _ => Ok((var.clone(), None)),
                }
            } else { Err(LookupError::Unreachable) }
        } else if self.tag == ScopeTag::Call {
            // A nonexistent binding in the current scope might require searching
            // the scope tree upwards for the binding. However, if the current
            // scope is a function call, it does not have access to anything from
            // its parent scope, so it should not do this lookup. If the overall
            // lookup fails, the ScopeManager will check the global scope.
            Err(LookupError::FnBoundary)
        } else {
            Err(LookupError::CheckParent)
        }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        if !self.locals.contains_key(&var.binding) {
            // Variable was not allocated.
            return Err(GcError::Store(var, ptr));
        }
        match var.t {
            JsType::JsPtr(ref tag) =>
                if let Some(ref ptr) = ptr {
                    // If the pointer and its underlying type are not equal, return an error.
                    if !tag.eq_ptr_type(&ptr) { return Err(GcError::PtrAlloc); }
                    // TODO FIXME? cloning ptr is potentially expensive
                    // A new root was potentially created
                    self.heap.borrow_mut().update_ptr(&var.unique, ptr.clone())?;
                } else {
                    return Err(GcError::PtrAlloc);
                },
            _ => {
                if let Some(_) = ptr {
                    return Err(GcError::PtrAlloc);
                }
                // A root was potentially removed.
                // Blindly accept this Result, since we have no information
                // about the type we're overwriting, and if we fail to condemn
                // a stack-allocated variable that's completely fine, since the
                // heap doesn't store those anyway.
                self.heap.borrow_mut().condemn(var.unique.clone()).ok();
            },
        }
        // Update the variable on the stack
        if let Entry::Occupied(mut view) = self.stack.entry(var.unique.clone()) {
            *view.get_mut() = var;
            Ok(())
        } else {
            Err(GcError::Store(var, ptr))
        }
    }

    pub fn trigger_gc(&mut self) {
        // The interpreter says we can GC now
        self.heap.borrow_mut().mark_ptrs();
        self.heap.borrow_mut().sweep_ptrs();
        // Pop any variables we just deleted
        // TODO rewrite this to not have to clone keys, if possible
        let locals: Vec<_> = self.locals.keys().cloned().collect();
        for bnd in &locals {
            if let Some(unique) = self.locals.remove(bnd) {
                if self.heap.borrow().find_id(&unique).is_none() {
                    self.stack.remove(&unique);
                }
            }
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, parent: &mut Scope, returning_closure: bool) -> Result<HashSet<JsVar>> {
        let mut globals = HashSet::new();
        for (local, unique) in self.locals.drain() {
            let var = match self.stack.remove(&unique) {
                Some(var) => var,
                None => return Err(GcError::Scope),
            };
            if self.maybe_globals.contains(&local) {
                // Don't give global variables to the parent scope. Return them
                // so they may be properly stored.
                globals.insert(var);
            } else {
                if returning_closure {
                    // If we're returning a closure, conservatively assume the
                    // closure takes ownership of every binding defined in this
                    // scope, so it must all live into the parent scope.
                    parent.rebind_var(local, unique, var);
                } else {
                    // If not returning a closure, rebind all heap-allocated
                    // variables into the parent scope, so they may be GC'd at a
                    // later time.
                    if let JsType::JsPtr(_) = var.t {
                        parent.rebind_var(local, unique, var);
                    }
                }
            }
        }
        Ok(globals)
    }
}

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

    use gc_error::GcError;
    use js_types::js_var::{JsVar, JsPtrEnum, JsKey, JsType};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_push_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (var, ptr) = test_utils::make_str("test");
        assert!(test_scope.push_var(var, Some(ptr)).is_ok());
        assert_eq!(test_scope.heap.borrow().len(), 1);
        let var = test_utils::make_num(1.);
        assert!(test_scope.push_var(var, None).is_ok());
        assert_eq!(test_scope.heap.borrow().len(), 1);
    }

    #[test]
    fn test_push_var_fail() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (var, ptr) = test_utils::make_str("test");
        let res = test_scope.push_var(var, None);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
        assert!(test_scope.heap.borrow().is_empty());
        let var = test_utils::make_num(1.);
        let res = test_scope.push_var(var, Some(ptr));
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
        assert!(test_scope.heap.borrow().is_empty());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        test_scope.push_var(x, Some(x_ptr)).unwrap();

        let copy = test_scope.get_var_copy(&x_bnd);
        assert!(copy.is_ok());
        let (var_copy, ptr_copy) = copy.unwrap();
        assert!(matches!(var_copy, JsVar { t: JsType::JsPtr(_), .. }));
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_get_var_copy_fail() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(ScopeTag::Block, &heap);
        let copy = test_scope.get_var_copy(&Binding::new("".to_string()));
        assert!(copy.is_err());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        assert!(test_scope.push_var(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd).unwrap();
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update, update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd).unwrap();
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => unreachable!(),
        }
        assert_eq!(update.unique, *test_scope.locals.get(&x_bnd).unwrap());
    }

    #[test]
    fn test_update_var_fail() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        assert!(test_scope.push_var(x, Some(x_ptr)).is_ok());
        let (mut update, update_ptr) = test_scope.get_var_copy(&x_bnd).unwrap();
        let res = test_scope.update_var(update.clone(), None);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));

        update.t = JsType::JsNum(1.);
        let res = test_scope.update_var(update, update_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
    }

    #[test]
    fn test_transfer_stack_no_closure() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(ScopeTag::Block, &heap);
        {
            let mut test_scope = Scope::new(ScopeTag::Block, &heap);
            test_scope.push_var(test_utils::make_num(0.), None).unwrap();
            test_scope.push_var(test_utils::make_num(1.), None).unwrap();
            test_scope.push_var(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::JsSym("true".to_string()),
                            test_utils::make_num(1.), None)];
            let (var, ptr) = test_utils::make_obj(kvs, heap.clone());
            test_scope.push_var(var, Some(ptr)).unwrap();
            test_scope.transfer_stack(&mut parent_scope, false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }

    #[test]
    fn test_transfer_stack_return_closure() {
        let heap = test_utils::make_alloc_box();
        let mut closure_scope = Scope::new(ScopeTag::Block, &heap);
        let fn_unique = {
            // Create a child scope
            let mut test_scope = Scope::new(ScopeTag::Block, &heap);

            // Create a function object
            let (var, test_fn) = test_utils::make_fn(&Some("test".to_owned()), &Vec::new());
            let fn_unique = var.unique.clone();

            // Alocate the function
            test_scope.push_var(var, Some(test_fn)).unwrap();

            // Create and allocate a number
            test_scope.push_var(test_utils::make_num(1.), None).unwrap();

            // Create and allocate a string
            let (var, ptr) = test_utils::make_str("test");
            test_scope.push_var(var, Some(ptr)).unwrap();

            // Kill the current scope, signalling that we're returning a closure
            test_scope.transfer_stack(&mut closure_scope, true).unwrap();
            fn_unique
        };
        // The closure scope should contain the entire environment of the old scope
        assert_eq!(closure_scope.stack.len(), 3);
        // The heap should contain a string and a function
        assert_eq!(heap.borrow().len(), 2);
        // The function should still be allocated
        assert!(heap.borrow().find_id(&fn_unique).is_some());
    }
}
<commit_msg>Collapse else branch in Scope::transfer_stack as per Clippy<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;
use std::result;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::{Binding, UniqueBinding};
use js_types::allocator::Allocator;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    heap: Rc<RefCell<AllocBox>>,
    locals: HashMap<Binding, UniqueBinding>,
    stack: HashMap<UniqueBinding, JsVar>,
    maybe_globals: HashSet<Binding>,
    tag: ScopeTag,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ScopeTag {
    Call,
    Block,
}

#[derive(Copy, Clone, Debug)]
pub enum LookupError {
    Unreachable,
    FnBoundary,
    CheckParent,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(tag: ScopeTag, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            heap: heap.clone(),
            locals: HashMap::new(),
            stack: HashMap::new(),
            maybe_globals: HashSet::new(),
            tag: tag,
        }
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.stack.len()
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        if self.locals.contains_key(&var.binding) {
            // If the variable we're trying to create was already allocated,
            // just update its value and mark it as non-global.
            self.maybe_globals.remove(&var.binding);
            return self.update_var(var, ptr);
        }
        // Maybe insert the variable's pointer data into the heap
        let res = match var.t {
            JsType::JsPtr(_) =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.heap.borrow_mut().alloc(var.unique.clone(), ptr)
                } else {
                    return Err(GcError::PtrAlloc);
                },
            _ => if let Some(_) = ptr { Err(GcError::PtrAlloc) } else { Ok(()) },
        };
        self.bind_var(var);
        res
    }

    /// Push an already-allocated JsVar onto the stack.
    pub fn bind_var(&mut self, var: JsVar) {
        // Create a mapping from the local binding to the unique binding
        self.locals.insert(var.binding.clone(), var.unique.clone());
        // Push the unique binding onto the stack
        self.stack.insert(var.unique.clone(), var);
    }

    fn rebind_var(&mut self, local: Binding, unique: UniqueBinding, var: JsVar) {
        self.locals.insert(local, unique.clone());
        self.stack.insert(unique, var);
    }

    pub fn mark_global(&mut self, binding: &Binding) {
        self.maybe_globals.insert(binding.clone());
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, local: &Binding) -> result::Result<(JsVar, Option<JsPtrEnum>), LookupError> {
        if let Some(unique) = self.locals.get(local) {
            if let Some(var) = self.stack.get(unique) {
                match var.t {
                    JsType::JsPtr(_) => {
                        if let Some(alloc) = self.heap.borrow().find_id(unique) {
                            Ok((var.clone(), Some(alloc.borrow().clone())))
                        } else {
                            // This case should be impossible unless you have an
                            // invalid ptr, which should also be impossible.
                            Err(LookupError::Unreachable)
                        }
                    },
                    _ => Ok((var.clone(), None)),
                }
            } else { Err(LookupError::Unreachable) }
        } else if self.tag == ScopeTag::Call {
            // A nonexistent binding in the current scope might require searching
            // the scope tree upwards for the binding. However, if the current
            // scope is a function call, it does not have access to anything from
            // its parent scope, so it should not do this lookup. If the overall
            // lookup fails, the ScopeManager will check the global scope.
            Err(LookupError::FnBoundary)
        } else {
            Err(LookupError::CheckParent)
        }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        if !self.locals.contains_key(&var.binding) {
            // Variable was not allocated.
            return Err(GcError::Store(var, ptr));
        }
        match var.t {
            JsType::JsPtr(ref tag) =>
                if let Some(ref ptr) = ptr {
                    // If the pointer and its underlying type are not equal, return an error.
                    if !tag.eq_ptr_type(&ptr) { return Err(GcError::PtrAlloc); }
                    // TODO FIXME? cloning ptr is potentially expensive
                    // A new root was potentially created
                    self.heap.borrow_mut().update_ptr(&var.unique, ptr.clone())?;
                } else {
                    return Err(GcError::PtrAlloc);
                },
            _ => {
                if let Some(_) = ptr {
                    return Err(GcError::PtrAlloc);
                }
                // A root was potentially removed.
                // Blindly accept this Result, since we have no information
                // about the type we're overwriting, and if we fail to condemn
                // a stack-allocated variable that's completely fine, since the
                // heap doesn't store those anyway.
                self.heap.borrow_mut().condemn(var.unique.clone()).ok();
            },
        }
        // Update the variable on the stack
        if let Entry::Occupied(mut view) = self.stack.entry(var.unique.clone()) {
            *view.get_mut() = var;
            Ok(())
        } else {
            Err(GcError::Store(var, ptr))
        }
    }

    pub fn trigger_gc(&mut self) {
        // The interpreter says we can GC now
        self.heap.borrow_mut().mark_ptrs();
        self.heap.borrow_mut().sweep_ptrs();
        // Pop any variables we just deleted
        // TODO rewrite this to not have to clone keys, if possible
        let locals: Vec<_> = self.locals.keys().cloned().collect();
        for bnd in &locals {
            if let Some(unique) = self.locals.remove(bnd) {
                if self.heap.borrow().find_id(&unique).is_none() {
                    self.stack.remove(&unique);
                }
            }
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, parent: &mut Scope, returning_closure: bool) -> Result<HashSet<JsVar>> {
        let mut globals = HashSet::new();
        for (local, unique) in self.locals.drain() {
            let var = match self.stack.remove(&unique) {
                Some(var) => var,
                None => return Err(GcError::Scope),
            };
            if self.maybe_globals.contains(&local) {
                // Don't give global variables to the parent scope. Return them
                // so they may be properly stored.
                globals.insert(var);
            } else if returning_closure {
                // If we're returning a closure, conservatively assume the
                // closure takes ownership of every binding defined in this
                // scope, so it must all live into the parent scope.
                parent.rebind_var(local, unique, var);
            } else {
                // If not returning a closure, rebind all heap-allocated
                // variables into the parent scope, so they may be GC'd at a
                // later time.
                if let JsType::JsPtr(_) = var.t {
                    parent.rebind_var(local, unique, var);
                }
            }
        }
        Ok(globals)
    }
}

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

    use gc_error::GcError;
    use js_types::js_var::{JsVar, JsPtrEnum, JsKey, JsType};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_push_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (var, ptr) = test_utils::make_str("test");
        assert!(test_scope.push_var(var, Some(ptr)).is_ok());
        assert_eq!(test_scope.heap.borrow().len(), 1);
        let var = test_utils::make_num(1.);
        assert!(test_scope.push_var(var, None).is_ok());
        assert_eq!(test_scope.heap.borrow().len(), 1);
    }

    #[test]
    fn test_push_var_fail() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (var, ptr) = test_utils::make_str("test");
        let res = test_scope.push_var(var, None);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
        assert!(test_scope.heap.borrow().is_empty());
        let var = test_utils::make_num(1.);
        let res = test_scope.push_var(var, Some(ptr));
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
        assert!(test_scope.heap.borrow().is_empty());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        test_scope.push_var(x, Some(x_ptr)).unwrap();

        let copy = test_scope.get_var_copy(&x_bnd);
        assert!(copy.is_ok());
        let (var_copy, ptr_copy) = copy.unwrap();
        assert!(matches!(var_copy, JsVar { t: JsType::JsPtr(_), .. }));
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_get_var_copy_fail() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(ScopeTag::Block, &heap);
        let copy = test_scope.get_var_copy(&Binding::new("".to_string()));
        assert!(copy.is_err());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        assert!(test_scope.push_var(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd).unwrap();
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update, update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd).unwrap();
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => unreachable!(),
        }
        assert_eq!(update.unique, *test_scope.locals.get(&x_bnd).unwrap());
    }

    #[test]
    fn test_update_var_fail() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(ScopeTag::Block, &heap);
        let (x, x_ptr) = test_utils::make_str("x");
        let x_bnd = x.binding.clone();
        assert!(test_scope.push_var(x, Some(x_ptr)).is_ok());
        let (mut update, update_ptr) = test_scope.get_var_copy(&x_bnd).unwrap();
        let res = test_scope.update_var(update.clone(), None);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));

        update.t = JsType::JsNum(1.);
        let res = test_scope.update_var(update, update_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::PtrAlloc)));
    }

    #[test]
    fn test_transfer_stack_no_closure() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(ScopeTag::Block, &heap);
        {
            let mut test_scope = Scope::new(ScopeTag::Block, &heap);
            test_scope.push_var(test_utils::make_num(0.), None).unwrap();
            test_scope.push_var(test_utils::make_num(1.), None).unwrap();
            test_scope.push_var(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::JsSym("true".to_string()),
                            test_utils::make_num(1.), None)];
            let (var, ptr) = test_utils::make_obj(kvs, heap.clone());
            test_scope.push_var(var, Some(ptr)).unwrap();
            test_scope.transfer_stack(&mut parent_scope, false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }

    #[test]
    fn test_transfer_stack_return_closure() {
        let heap = test_utils::make_alloc_box();
        let mut closure_scope = Scope::new(ScopeTag::Block, &heap);
        let fn_unique = {
            // Create a child scope
            let mut test_scope = Scope::new(ScopeTag::Block, &heap);

            // Create a function object
            let (var, test_fn) = test_utils::make_fn(&Some("test".to_owned()), &Vec::new());
            let fn_unique = var.unique.clone();

            // Alocate the function
            test_scope.push_var(var, Some(test_fn)).unwrap();

            // Create and allocate a number
            test_scope.push_var(test_utils::make_num(1.), None).unwrap();

            // Create and allocate a string
            let (var, ptr) = test_utils::make_str("test");
            test_scope.push_var(var, Some(ptr)).unwrap();

            // Kill the current scope, signalling that we're returning a closure
            test_scope.transfer_stack(&mut closure_scope, true).unwrap();
            fn_unique
        };
        // The closure scope should contain the entire environment of the old scope
        assert_eq!(closure_scope.stack.len(), 3);
        // The heap should contain a string and a function
        assert_eq!(heap.borrow().len(), 2);
        // The function should still be allocated
        assert!(heap.borrow().find_id(&fn_unique).is_some());
    }
}
<|endoftext|>


<commit_before>use capnp;
use capnp::message::MessageBuilder;
use zmq;
use std;
use rand::Rng;
use capnp_zmq;
use explorers_capnp::observation;
use time;

struct Pixel {
    red : u8,
    green : u8,
    blue : u8
}

impl Copy for Pixel {}

fn fudge(x : u8) -> u8 {
    let error = ::rand::thread_rng().gen_range::<i16>(-60, 60);
    let y = x as i16 + error;
    if y < 0 { return 0; }
    if y > 255 { return 255; }
    return y as u8;
}

struct Image {
    width : u32,
    height : u32,
    pixels : Vec<Pixel>
}

impl Image {

    // quick and dirty parsing of a PPM image
    fn load(file : &std::path::Path) -> std::io::Result<Image> {
        use std::io::{BufRead, Read};
        let file = try!(std::fs::File::open(file));
        let mut buffered = ::std::io::BufReader::new(file);
        let mut line = String::new();
        try!(buffered.read_line(&mut line));
        assert!(line.trim() == "P6");
        try!(buffered.read_line(&mut line));

        let (width, height) : (u32, u32) = {
            let dims : Vec<&str> = line.split(' ').collect();
            assert!(dims.len() == 2, "could not read dimensions");
            (::std::str::FromStr::from_str(dims[0].trim()).unwrap(),
             ::std::str::FromStr::from_str(dims[1].trim()).unwrap())
        };

        try!(buffered.read_line(&mut line));
        assert!(line.trim() == "255");

        let mut result = Image { width : width, height : height, pixels : Vec::new() };

        let mut bytes = buffered.bytes();

        for _ in 0..width * height {
            result.pixels.push(
                Pixel {
                    red : try!(bytes.next().expect("error reading red value")),
                    green : try!(bytes.next().expect("error reading green value")),
                    blue : try!(bytes.next().expect("error reading blue value")),
                });
        }
        return Ok(result);
    }

    fn get_pixel(&self, x : u32, y : u32) -> Pixel {
        assert!(x < self.width);
        assert!(y < self.height);
        self.pixels[((y * self.width) + x) as usize]
    }

    fn take_measurement(&self, x : f32, y : f32, mut obs : observation::Builder) {
        use std::num::Float;
        assert!(x >= 0.0); assert!(y >= 0.0); assert!(x < 1.0); assert!(y < 1.0);

        obs.set_timestamp(time::now().to_timespec().sec);
        obs.set_x(x);
        obs.set_y(y);

        let pixel = self.get_pixel((x * self.width as f32).floor() as u32,
                                   (y * self.height as f32).floor() as u32);

        obs.set_red(fudge(pixel.red));
        obs.set_green(fudge(pixel.green));
        obs.set_blue(fudge(pixel.blue));

        add_diagnostic(obs);
    }
}

static WORDS : [&'static str; 20] = [
   "syntax", "personality", "rhymist", "shopwalker", "gooseskin", "overtask",
    "churme", "heathen", "economiser", "radium", "attainable", "nonius", "knaggy",
    "inframedian", "tamperer", "disentitle", "horary", "morsure", "bonnaz", "alien",
];

// With small probability, add a gibberish warning to the observation.
fn add_diagnostic<'a>(obs : observation::Builder<'a>) {
    let mut rng = ::rand::thread_rng();
    if rng.gen_range::<u16>(0, 3000) < 2 {
        let mut warning = String::new();
        warning.push_str(*rng.choose(&WORDS).unwrap());
        warning.push_str(" ");
        warning.push_str(&rng.gen_ascii_chars().take(8).collect::<String>());
        warning.push_str(" ");
        warning.push_str(*rng.choose(&WORDS).unwrap());
        obs.init_diagnostic().set_warning(&warning);
    }
}

pub fn main () -> Result<(), zmq::Error> {

    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {:?} explorer [filename]", args.get(0));
        return Ok(());
    }

    let image = Image::load(&std::path::Path::new(&args[2])).unwrap();

    let mut context = zmq::Context::new();
    let mut publisher = try!(context.socket(zmq::PUB));
    try!(publisher.connect("tcp://localhost:5555"));

    let mut rng = ::rand::thread_rng();
    let mut x = rng.gen_range::<f32>(0.0, 1.0);
    let mut y = rng.gen_range::<f32>(0.0, 1.0);

    loop {
        x += rng.gen_range::<f32>(-0.01, 0.01);
        y += rng.gen_range::<f32>(-0.01, 0.01);

        if x >= 1.0 { x -= 1.0 }
        if y >= 1.0 { y -= 1.0 }
        if x < 0.0 { x += 1.0 }
        if y < 0.0 { y += 1.0 }

        let mut message = capnp::message::MallocMessageBuilder::new_default();
        {
            let obs = message.init_root::<observation::Builder>();
            image.take_measurement(x, y, obs);
        }
        try!(capnp_zmq::send(&mut publisher, &mut message));

        // XXX we need thread::sleep
        //std::io::timer::sleep(std::time::Duration::milliseconds(5));
    }

}
<commit_msg>example kinda works now<commit_after>use capnp;
use capnp::message::MessageBuilder;
use zmq;
use std;
use rand::Rng;
use capnp_zmq;
use explorers_capnp::observation;
use time;

struct Pixel {
    red : u8,
    green : u8,
    blue : u8
}

impl Copy for Pixel {}

fn fudge(x : u8) -> u8 {
    let error = ::rand::thread_rng().gen_range::<i16>(-60, 60);
    let y = x as i16 + error;
    if y < 0 { return 0; }
    if y > 255 { return 255; }
    return y as u8;
}

struct Image {
    width : u32,
    height : u32,
    pixels : Vec<Pixel>
}

impl Image {

    // quick and dirty parsing of a PPM image
    fn load(file : &std::path::Path) -> std::io::Result<Image> {
        use std::io::{BufRead, Read};
        let file = try!(std::fs::File::open(file));
        let mut buffered = ::std::io::BufReader::new(file);
        let mut line = String::new();
        try!(buffered.read_line(&mut line));
        assert!(line.trim() == "P6");
        line.clear();

        try!(buffered.read_line(&mut line));
        let (width, height) : (u32, u32) = {
            let dims : Vec<&str> = line.split(' ').collect();
            assert!(dims.len() == 2, "could not read dimensions");
            (::std::str::FromStr::from_str(dims[0].trim()).unwrap(),
             ::std::str::FromStr::from_str(dims[1].trim()).unwrap())
        };
        line.clear();

        try!(buffered.read_line(&mut line));
        assert!(line.trim() == "255");
        line.clear();

        let mut result = Image { width : width, height : height, pixels : Vec::new() };
        let mut bytes = buffered.bytes();
        for _ in 0..width * height {
            result.pixels.push(
                Pixel {
                    red : try!(bytes.next().expect("error reading red value")),
                    green : try!(bytes.next().expect("error reading green value")),
                    blue : try!(bytes.next().expect("error reading blue value")),
                });
        }
        return Ok(result);
    }

    fn get_pixel(&self, x : u32, y : u32) -> Pixel {
        assert!(x < self.width);
        assert!(y < self.height);
        self.pixels[((y * self.width) + x) as usize]
    }

    fn take_measurement(&self, x : f32, y : f32, mut obs : observation::Builder) {
        use std::num::Float;
        assert!(x >= 0.0); assert!(y >= 0.0); assert!(x < 1.0); assert!(y < 1.0);

        obs.set_timestamp(time::now().to_timespec().sec);
        obs.set_x(x);
        obs.set_y(y);

        let pixel = self.get_pixel((x * self.width as f32).floor() as u32,
                                   (y * self.height as f32).floor() as u32);

        obs.set_red(fudge(pixel.red));
        obs.set_green(fudge(pixel.green));
        obs.set_blue(fudge(pixel.blue));

        add_diagnostic(obs);
    }
}

static WORDS : [&'static str; 20] = [
   "syntax", "personality", "rhymist", "shopwalker", "gooseskin", "overtask",
    "churme", "heathen", "economiser", "radium", "attainable", "nonius", "knaggy",
    "inframedian", "tamperer", "disentitle", "horary", "morsure", "bonnaz", "alien",
];

// With small probability, add a gibberish warning to the observation.
fn add_diagnostic<'a>(obs : observation::Builder<'a>) {
    let mut rng = ::rand::thread_rng();
    if rng.gen_range::<u16>(0, 3000) < 2 {
        let mut warning = String::new();
        warning.push_str(*rng.choose(&WORDS).unwrap());
        warning.push_str(" ");
        warning.push_str(&rng.gen_ascii_chars().take(8).collect::<String>());
        warning.push_str(" ");
        warning.push_str(*rng.choose(&WORDS).unwrap());
        obs.init_diagnostic().set_warning(&warning);
    }
}

pub fn main () -> Result<(), zmq::Error> {

    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {:?} explorer [filename]", args.get(0));
        return Ok(());
    }

    let image = Image::load(&std::path::Path::new(&args[2])).unwrap();

    let mut context = zmq::Context::new();
    let mut publisher = try!(context.socket(zmq::PUB));
    try!(publisher.connect("tcp://localhost:5555"));

    let mut rng = ::rand::thread_rng();
    let mut x = rng.gen_range::<f32>(0.0, 1.0);
    let mut y = rng.gen_range::<f32>(0.0, 1.0);

    loop {
        x += rng.gen_range::<f32>(-0.01, 0.01);
        y += rng.gen_range::<f32>(-0.01, 0.01);

        if x >= 1.0 { x -= 1.0 }
        if y >= 1.0 { y -= 1.0 }
        if x < 0.0 { x += 1.0 }
        if y < 0.0 { y += 1.0 }

        let mut message = capnp::message::MallocMessageBuilder::new_default();
        {
            let obs = message.init_root::<observation::Builder>();
            image.take_measurement(x, y, obs);
        }
        try!(capnp_zmq::send(&mut publisher, &mut message));

        // TODO switch to thread::sleep once it exists.
        unsafe {
            let req = ::libc::types::os::common::posix01::timespec {
                tv_sec : 0,
                tv_nsec : 5000000, // 5 milliseconds
            };
            ::libc::funcs::posix88::unistd::nanosleep(&req, ::std::ptr::null_mut());
        }
    }

}
<|endoftext|>


<commit_before>use {osc_types as ot,
    errors as oe};

use std::{io, string, mem, error};
use std::io::BufRead;

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);
    let mut pos: u64 = 0;

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            println!("{}",try!(read_osc_string(&mut cursor)));
        }
        Err(e) => {
            println!("{}", e)
        }
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf).map_err(|e| oe::OscError::StringError(e))
        },
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}<commit_msg>Return OscError<commit_after>use {osc_types as ot,
    errors as oe};

use std::{io, string, mem, error};
use std::io::BufRead;

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);
    let mut pos: u64 = 0;

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            println!("{}",try!(read_osc_string(&mut cursor)));
        }
        Err(e) => {
            return Err(e)
        }
        Err(e) => return Err(e)
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf).map_err(|e| oe::OscError::StringError(e))
        },
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}<|endoftext|>


<commit_before>use crate::types::TypeNum;
use pyo3::{ffi, typeob, types::PyObjectRef, PyObjectAlloc, Python, ToPyPointer};
use std::os::raw::c_void;

#[repr(C)]
pub(crate) struct SliceBox<T> {
    ob_base: ffi::PyObject,
    inner: *mut [T],
}

impl<T> SliceBox<T> {
    pub(crate) unsafe fn new<'a>(box_: Box<[T]>) -> &'a Self {
        <Self as typeob::PyTypeObject>::init_type();
        let type_ob = <Self as typeob::PyTypeInfo>::type_object() as *mut _;
        let base = ffi::_PyObject_New(type_ob);
        *base = ffi::PyObject_HEAD_INIT;
        (*base).ob_type = type_ob;
        let self_ = base as *mut SliceBox<T>;
        (*self_).inner = Box::into_raw(box_);
        &*self_
    }
    pub(crate) fn data(&self) -> *mut c_void {
        self.inner as *mut c_void
    }
}

impl<T> typeob::PyTypeInfo for SliceBox<T> {
    type Type = ();
    type BaseType = PyObjectRef;
    const NAME: &'static str = "SliceBox";
    const DESCRIPTION: &'static str = "Memory store for PyArray made by IntoPyArray.";
    const FLAGS: usize = 0;
    const SIZE: usize = { Self::OFFSET as usize + std::mem::size_of::<Self>() + 0 + 0 };
    const OFFSET: isize = 0;
    #[inline]
    unsafe fn type_object() -> &'static mut ffi::PyTypeObject {
        static mut TYPE_OBJECT: ::pyo3::ffi::PyTypeObject = ::pyo3::ffi::PyTypeObject_INIT;
        &mut TYPE_OBJECT
    }
}

impl<T: TypeNum> typeob::PyTypeCreate for SliceBox<T> {
    #[inline(always)]
    fn init_type() {
        static START: std::sync::Once = std::sync::ONCE_INIT;
        START.call_once(|| {
            let ty = unsafe { <Self as typeob::PyTypeInfo>::type_object() };
            if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
                let gil = Python::acquire_gil();
                let py = gil.python();
                let mod_name = format!("rust_numpy.{:?}", T::npy_data_type());
                typeob::initialize_type::<Self>(py, Some(&mod_name))
                    .map_err(|e| e.print(py))
                    .expect("Failed to initialize SliceBox");
            }
        });
    }
}

impl<T> ToPyPointer for SliceBox<T> {
    #[inline]
    fn as_ptr(&self) -> *mut ffi::PyObject {
        &self.ob_base as *const _ as *mut _
    }
}

impl<T> PyObjectAlloc<SliceBox<T>> for SliceBox<T> {
    /// Calls the rust destructor for the object.
    unsafe fn drop(py: Python, obj: *mut ffi::PyObject) {
        let data = (*(obj as *mut SliceBox<T>)).inner;
        let boxed_slice = Box::from_raw(data);
        drop(boxed_slice);
        <Self as typeob::PyTypeInfo>::BaseType::drop(py, obj);
    }
    unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
        Self::drop(py, obj);
        ffi::PyObject_Free(obj as *mut c_void);
    }
}
<commit_msg>Simplify impl PyTypeInfo for SliceBox<commit_after>use crate::types::TypeNum;
use pyo3::{ffi, typeob, types::PyObjectRef, PyObjectAlloc, Python, ToPyPointer};
use std::os::raw::c_void;

/// It's a memory store for IntoPyArray.
/// See IntoPyArray's doc for what concretely this type is for.
#[repr(C)]
pub(crate) struct SliceBox<T> {
    ob_base: ffi::PyObject,
    inner: *mut [T],
}

impl<T> SliceBox<T> {
    pub(crate) unsafe fn new<'a>(box_: Box<[T]>) -> &'a Self {
        <Self as typeob::PyTypeObject>::init_type();
        let type_ob = <Self as typeob::PyTypeInfo>::type_object() as *mut _;
        let base = ffi::_PyObject_New(type_ob);
        *base = ffi::PyObject_HEAD_INIT;
        (*base).ob_type = type_ob;
        let self_ = base as *mut SliceBox<T>;
        (*self_).inner = Box::into_raw(box_);
        &*self_
    }
    pub(crate) fn data(&self) -> *mut c_void {
        self.inner as *mut c_void
    }
}

impl<T> typeob::PyTypeInfo for SliceBox<T> {
    type Type = ();
    type BaseType = PyObjectRef;
    const NAME: &'static str = "SliceBox";
    const DESCRIPTION: &'static str = "Memory store for PyArray using rust's Box<[T]>.";
    const FLAGS: usize = 0;
    const SIZE: usize = std::mem::size_of::<Self>();
    const OFFSET: isize = 0;
    #[inline]
    unsafe fn type_object() -> &'static mut ffi::PyTypeObject {
        static mut TYPE_OBJECT: ::pyo3::ffi::PyTypeObject = ::pyo3::ffi::PyTypeObject_INIT;
        &mut TYPE_OBJECT
    }
}

impl<T: TypeNum> typeob::PyTypeCreate for SliceBox<T> {
    #[inline(always)]
    fn init_type() {
        static START: std::sync::Once = std::sync::ONCE_INIT;
        START.call_once(|| {
            let ty = unsafe { <Self as typeob::PyTypeInfo>::type_object() };
            if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
                let gil = Python::acquire_gil();
                let py = gil.python();
                let mod_name = format!("rust_numpy.{:?}", T::npy_data_type());
                typeob::initialize_type::<Self>(py, Some(&mod_name))
                    .map_err(|e| e.print(py))
                    .expect("Failed to initialize SliceBox");
            }
        });
    }
}

impl<T> ToPyPointer for SliceBox<T> {
    #[inline]
    fn as_ptr(&self) -> *mut ffi::PyObject {
        &self.ob_base as *const _ as *mut _
    }
}

impl<T> PyObjectAlloc<SliceBox<T>> for SliceBox<T> {
    /// Calls the rust destructor for the object.
    unsafe fn drop(py: Python, obj: *mut ffi::PyObject) {
        let data = (*(obj as *mut SliceBox<T>)).inner;
        let boxed_slice = Box::from_raw(data);
        drop(boxed_slice);
        <Self as typeob::PyTypeInfo>::BaseType::drop(py, obj);
    }
    unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
        Self::drop(py, obj);
        ffi::PyObject_Free(obj as *mut c_void);
    }
}
<|endoftext|>