<commit_before>#![cfg_attr(test, allow(dead_code))]

#![feature(collections)]
#![feature(io)]
#![feature(env)]
#![feature(path)]
#![feature(rustc_private)]

extern crate document;
extern crate xpath;
extern crate getopts;

use std::cmp::min;
use std::env;
use std::collections::HashMap;
use std::old_io::File;

use document::parser::Parser;

use xpath::nodeset::ToNode;
use xpath::{EvaluationContext,Factory,Expression};

use getopts::{reqopt,optmulti,getopts,OptGroup,usage};

fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options] FILE...", program);
    print!("{}", usage(&brief, opts));
}

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn build_xpath(xpath_str: &str) -> Box<Expression> {
    let factory = Factory::new();

    match factory.build(xpath_str) {
        Err(x) => panic!("Unable to compile XPath: {:?}", x),
        Ok(None) => panic!("Unable to compile XPath"),
        Ok(Some(x)) => x,
    }
}

fn load_xml(filename: &str) -> document::Package {
    let p = Parser::new();
    let path = Path::new(filename);
    let mut file = File::open(&path);

    let data = match file.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    }
}

fn build_functions() -> xpath::Functions {
    let mut functions = HashMap::new();
    xpath::function::register_core_functions(&mut functions);
    functions
}

fn build_variables<'a>() -> xpath::Variables<'a> {
    HashMap::new()
}

fn build_namespaces(arguments: &getopts::Matches) -> xpath::Namespaces {
    let mut namespaces = HashMap::new();
    for ns_defn in arguments.opt_strs("namespace").iter() {
        let parts: Vec<_> = ns_defn.splitn(2, ':').collect();
        if parts.len() < 2 {
            panic!("Namespace definition '{}' is malformed", ns_defn);
        }

        namespaces.insert(parts[0].to_string(), parts[1].to_string());
    }
    namespaces
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let program_name = &args[0];

    let opts = &[
        reqopt("", "xpath", "The XPath to execute", "XPATH"),
        optmulti("", "namespace", "set namespace prefix", "PREFIX:URI"),
    ];

    let arguments = match getopts(args.tail(), opts) {
        Ok(x) => x,
        Err(x) => {
            println!("{}", x);
            print_usage(program_name, opts);
            return;
        },
    };

    let xpath_str = arguments.opt_str("xpath").unwrap();
    let xpath = build_xpath(&xpath_str);

    for filename in arguments.free.iter() {
        let package = load_xml(filename);
        let doc = package.as_document();
        let root = doc.root().into_node();

        let functions = build_functions();
        let variables = build_variables();
        let namespaces = build_namespaces(&arguments);

        let context = EvaluationContext::new(
            root,
            &functions,
            &variables,
            &namespaces,
        );

        let res = xpath.evaluate(&context);

        println!("{:?}", res);
    }
}
<commit_msg>Allow setting variables from the command line<commit_after>#![cfg_attr(test, allow(dead_code))]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(env)]
#![feature(path)]
#![feature(rustc_private)]

extern crate document;
extern crate xpath;
extern crate getopts;

use std::cmp::min;
use std::borrow::ToOwned;
use std::env;
use std::collections::HashMap;
use std::old_io::File;

use document::parser::Parser;

use xpath::nodeset::ToNode;
use xpath::{EvaluationContext,Factory,Expression,Value};

use getopts::{reqopt,optmulti,getopts,OptGroup,usage};

fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options] FILE...", program);
    print!("{}", usage(&brief, opts));
}

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn build_xpath(xpath_str: &str) -> Box<Expression> {
    let factory = Factory::new();

    match factory.build(xpath_str) {
        Err(x) => panic!("Unable to compile XPath: {:?}", x),
        Ok(None) => panic!("Unable to compile XPath"),
        Ok(Some(x)) => x,
    }
}

fn load_xml(filename: &str) -> document::Package {
    let p = Parser::new();
    let path = Path::new(filename);
    let mut file = File::open(&path);

    let data = match file.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    }
}

fn argument_name_value(s: &str, delim: char) -> Option<(&str, &str)> {
    let parts: Vec<_> = s.splitn(2, delim).collect();
    if parts.len() < 2 {
        None
    } else {
        Some((parts[0], parts[1]))
    }
}

fn build_functions() -> xpath::Functions {
    let mut functions = HashMap::new();
    xpath::function::register_core_functions(&mut functions);
    functions
}

fn build_variables<'a>(arguments: &getopts::Matches) -> xpath::Variables<'a> {
    let mut vars = HashMap::new();

    for boolean in arguments.opt_strs("boolean") {
        match argument_name_value(&boolean, '=') {
            Some((name, "true")) => { vars.insert(name.to_owned(), Value::Boolean(true)); },
            Some((name, "false")) => { vars.insert(name.to_owned(), Value::Boolean(false)); },
            Some((_, val)) => panic!("Unknown boolean value '{}'", val),
            None => panic!("boolean argument '{}' is malformed", boolean),
        }
    }

    for number in arguments.opt_strs("number") {
        match argument_name_value(&number, '=') {
            Some((name, val)) => {
                match val.parse() {
                    Ok(val) => { vars.insert(name.to_owned(), Value::Number(val)); },
                    Err(e) => panic!("Unknown numeric value '{}': {}", val, e),
                }
            },
            None => panic!("number argument '{}' is malformed", number),
        }
    }

    for string in arguments.opt_strs("string") {
        match argument_name_value(&string, '=') {
            Some((name, val)) => { vars.insert(name.to_owned(), Value::String(val.to_owned())); },
            None => panic!("string argument '{}' is malformed", string),
        }
    }

    vars
}

fn build_namespaces(arguments: &getopts::Matches) -> xpath::Namespaces {
    let mut namespaces = HashMap::new();

    for ns_defn in arguments.opt_strs("namespace") {
        match argument_name_value(&ns_defn, ':') {
            Some((prefix, uri)) => { namespaces.insert(prefix.to_owned(), uri.to_owned()); },
            None => panic!("Namespace definition '{}' is malformed", ns_defn),
        }
    }

    namespaces
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let program_name = &args[0];

    let opts = &[
        reqopt("", "xpath", "The XPath to execute", "XPATH"),
        optmulti("", "namespace", "set namespace prefix", "PREFIX:URI"),
        optmulti("", "string", "set string variable", "NAME=VALUE"),
        optmulti("", "number", "set number variable", "NAME=VALUE"),
        optmulti("", "boolean", "set boolean variable", "NAME=VALUE"),
    ];

    let arguments = match getopts(args.tail(), opts) {
        Ok(x) => x,
        Err(x) => {
            println!("{}", x);
            print_usage(program_name, opts);
            return;
        },
    };

    let xpath_str = arguments.opt_str("xpath").unwrap();
    let xpath = build_xpath(&xpath_str);

    for filename in arguments.free.iter() {
        let package = load_xml(filename);
        let doc = package.as_document();
        let root = doc.root().into_node();

        let functions = build_functions();
        let variables = build_variables(&arguments);
        let namespaces = build_namespaces(&arguments);

        let context = EvaluationContext::new(
            root,
            &functions,
            &variables,
            &namespaces,
        );

        let res = xpath.evaluate(&context);

        println!("{:?}", res);
    }
}
<|endoftext|>


<commit_before>use binding::util;
use types;

use super::{array, class, object, string};

pub trait RawObject {
    fn from_value(value: types::rb_value) -> Self;

    fn value(&self) -> types::rb_value;

    fn as_array(&self) -> array::Array {
        array::Array::from_value(self.value())
    }

    fn as_class(&self) -> class::Class {
        class::Class::from_value(self.value())
    }

    fn as_string(&self) -> string::RString {
        string::RString::from_value(self.value())
    }

    fn send<T: RawObject>(&self, method: &str, arguments: Vec<T>) -> object::Object {
        let arguments = arguments.iter().map(|object| object.value()).collect();
        let result = util::call_method(self.value(), method, arguments);

        object::Object::from_value(result)
    }
}
<commit_msg>Create RawObject as_object()<commit_after>use binding::util;
use types;

use super::{array, class, object, string};

pub trait RawObject {
    fn from_value(value: types::rb_value) -> Self;

    fn value(&self) -> types::rb_value;

    fn as_object(&self) -> object::Object {
        object::Object::from_value(self.value())
    }

    fn as_array(&self) -> array::Array {
        array::Array::from_value(self.value())
    }

    fn as_class(&self) -> class::Class {
        class::Class::from_value(self.value())
    }

    fn as_string(&self) -> string::RString {
        string::RString::from_value(self.value())
    }

    fn send(&self, method: &str, arguments: Vec<object::Object>) -> object::Object {
        let arguments = arguments.iter().map(|object| object.value()).collect();
        let result = util::call_method(self.value(), method, arguments);

        object::Object::from_value(result)
    }
}
<|endoftext|>


<commit_before>use gfx;

use rustfft;
use rustfft::num_complex::Complex;

use std::f32;
use std::sync::Arc;

pub struct Spectro {
    bufsize: usize,
    fft: Arc<rustfft::FFT<f32>>
}

impl Spectro {
    pub fn new(bufsize: usize) -> Spectro {
        let mut planner = rustfft::FFTplanner::new(false);
        let mut window = vec![0f32; bufsize];

        Spectro {
            bufsize: bufsize,
            fft: planner.plan_fft(bufsize)
        }
    }

    pub fn draw(&self, signal: &[f32], surface: &mut gfx::Surface) {
        if signal.len() != self.bufsize {
            panic!()
        }

        let mut input = Vec::with_capacity(self.bufsize);
        for sample in signal {
            input.push(Complex { re: *sample, im: 0.0 });
        }
        let mut output = vec![Complex { re: 0.0, im: 0.0 }; self.bufsize];

        self.fft.process(&mut input, &mut output);

        let mut dbs = Vec::new();

        for value in &output {
            dbs.push(10f32 * (value.re * value.re + value.im * value.im).log10() / 10f32.log10());
        }

        let min_db = dbs.iter().cloned().fold(f32::NAN, f32::min);
        let max_db = dbs.iter().cloned().fold(f32::NAN, f32::max);

        let min_db_limit = 0f32;
        let max_db_limit = 100f32;

        surface.clear(gfx::Color { r: 0, g: 0, b: 0, a: 255 });

        println!("min, max db = {}, {}", min_db, max_db);

        for x in 0..surface.width {
            let mut db = dbs[((x as f64 / surface.width as f64) * output.len() as f64) as usize];
            if db < min_db_limit {
                db = min_db_limit;
            } else if db > max_db_limit {
                db = max_db_limit;
            }

            let scaled = (db - min_db_limit) / (max_db_limit - min_db_limit);
            let y = surface.height - (scaled * surface.height as f32) as usize - 1;

            if x < 3 {
                println!("x={} index={} db={} scaled={} y={}",
                         x,
                         ((x as f64 / surface.width as f64) * output.len() as f64) as usize,
                         db,
                         scaled,
                         y);
            }

            surface.point(x, y, gfx::Color { r: 255, g: 255, b: 255, a: 255 });
        }
    }
}
<commit_msg>Apply window function to signal, use map instead of vec.push<commit_after>use gfx;

use rustfft;
use rustfft::num_complex::Complex;

use std::f32;
use std::sync::Arc;

pub struct Spectro {
    bufsize: usize,
    window: Vec<f32>,
    fft: Arc<rustfft::FFT<f32>>
}

impl Spectro {
    pub fn new(bufsize: usize) -> Spectro {
        let window = (0..bufsize)
            .map(|i| ((f32::consts::PI * i as f32) / (bufsize - 1) as f32).sin().powi(2))
            .collect();
        let mut planner = rustfft::FFTplanner::new(false);

        Spectro {
            bufsize: bufsize,
            window: window,
            fft: planner.plan_fft(bufsize)
        }
    }

    pub fn draw(&self, signal: &[f32], surface: &mut gfx::Surface) {
        if signal.len() != self.bufsize {
            panic!()
        }

        // Multiply signal with the window function
        let mut input: Vec<Complex<f32>> = signal.iter().zip(&self.window)
            .map(|(sample, window_n)| Complex { re: sample * window_n, im: 0.0 })
            .collect();
        let mut output = vec![Complex { re: 0.0, im: 0.0 }; self.bufsize];

        self.fft.process(&mut input, &mut output);

        let dbs: Vec<f32> = output.iter()
            .map(|val| 10f32 * (val.re.powi(2) + val.im.powi(2)).log10() / 10f32.log10())
            .collect();

        let min_db = dbs.iter().cloned().fold(f32::NAN, f32::min);
        let max_db = dbs.iter().cloned().fold(f32::NAN, f32::max);

        let min_db_limit = 0f32;
        let max_db_limit = 100f32;

        surface.clear(gfx::Color { r: 0, g: 0, b: 0, a: 255 });

        println!("min, max db = {}, {}", min_db, max_db);

        for x in 0..surface.width {
            let mut db = dbs[((x as f64 / surface.width as f64) * output.len() as f64) as usize];
            if db < min_db_limit {
                db = min_db_limit;
            } else if db > max_db_limit {
                db = max_db_limit;
            }

            let scaled = (db - min_db_limit) / (max_db_limit - min_db_limit);
            let y = surface.height - (scaled * surface.height as f32) as usize - 1;

            if x < 3 {
                println!("x={} index={} db={} scaled={} y={}",
                         x,
                         ((x as f64 / surface.width as f64) * output.len() as f64) as usize,
                         db,
                         scaled,
                         y);
            }

            surface.point(x, y, gfx::Color { r: 255, g: 255, b: 255, a: 255 });
        }
    }
}
<|endoftext|>


<commit_before>use core::ops::Not;
use core::fmt::Debug;

use hardware::HardwareGpio;
use hardware::HardwareTime;
use hardware::PinMode;
use hardware::PinState;

const PULSE_LENGTH: u32 = 100;

#[derive(Debug)]
pub struct StepRateError {}

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    Forward = 1,
    Backward = -1,
}

impl Not for Direction {
    type Output = Direction;

    fn not(self) -> Direction {
        match self {
            Direction::Forward => Direction::Backward,
            Direction::Backward => Direction::Forward,
        }
    }
}

#[derive(Debug)]
pub struct StepperMotor<'a, H: 'a> {
    /// The current step that the motor is at
    current_step: i32,

    /// The current direction
    current_direction: Direction,

    /// The current traveling velocity in microseconds per step
    microseconds_per_step: u32,

    /// The number of steps per millimeter
    steps_per_millimeter: i32,

    /// The minimum of the stepper motor in mm
    min_travel: f32,

    /// The maximum of the stepper motor in mm
    max_travel: f32,

    /// The minimum number of steps that can be stepped
    min_steps: i32,

    /// The maxmimum number of steps that can be stepped
    max_steps: i32,

    /// The last time we stepped
    last_step: u32,

    /// If we are in the middle of a pulse
    mid_pulse: bool,

    /// The pin to use for stepping
    step_pin: u8,

    /// The pin to use for direction
    direction_pin: u8,

    /// The hardware to use to step the motor
    hardware: &'a mut H,
}

impl<'a, H: HardwareGpio + HardwareTime + Debug> StepperMotor<'a, H> {
    /// Make a new stepper motor
    pub fn new(
        steps_per_millimeter: i32,
        min_travel: f32,
        max_travel: f32,
        step_pin: u8,
        direction_pin: u8,
        hardware: &mut H,
    ) -> StepperMotor<H> {

        // Set the step and direction pins to output
        /*
        unsafe {
            bindings::pinMode(step_pin, bindings::OUTPUT as u8);
            bindings::pinMode(direction_pin, bindings::OUTPUT as u8);
        }
        */

        hardware.pin_mode(step_pin, PinMode::Output);
        hardware.pin_mode(direction_pin, PinMode::Output);

        StepperMotor {
            current_step: 0,
            current_direction: Direction::Backward,
            microseconds_per_step: 0,
            steps_per_millimeter: steps_per_millimeter,
            min_travel: min_travel,
            max_travel: max_travel,
            min_steps: (min_travel * steps_per_millimeter as f32) as i32,
            max_steps: (max_travel * steps_per_millimeter as f32) as i32,
            last_step: 0,
            mid_pulse: false,
            step_pin: step_pin,
            direction_pin: direction_pin,
            hardware: hardware,
        }
    }

    /// Get the max that this stepper can travel in mm
    pub fn get_max_travel(&self) -> f32 {
        self.max_travel
    }

    /// Get the min this stepper can travel in mm
    pub fn get_min_travel(&self) -> f32 {
        self.min_travel
    }

    /// Return the current position in mm
    pub fn get_current_position(&self) -> f32 {
        self.current_step as f32 / self.steps_per_millimeter as f32
    }

    /// Return the current velocity in mm/min
    pub fn get_current_velocity(&self) -> f32 {
        self.current_direction as i32 as f32 * 60000000.0 /
            (self.microseconds_per_step as i32 * self.steps_per_millimeter) as f32
    }

    /// Get the current direction
    pub fn get_current_direction(&self) -> Direction {
        self.current_direction
    }

    /// Set the max that this stepper can travel in mm
    pub fn set_max_travel(&mut self, max: f32) {
        self.max_travel = max;
        self.max_steps = (max * self.steps_per_millimeter as f32) as i32;
    }

    /// Set the min that this stepper can travel in mm
    pub fn set_min_travel(&mut self, min: f32) {
        self.min_travel = min;
        self.min_steps = (min * self.steps_per_millimeter as f32) as i32;
    }

    /// Set the current position (As in G92)
    /// Returns a `Result::Ok` with the now current step if successfull
    /// returns a `Result::Err` with the limit direction if the position is out of range
    pub fn set_current_position(&mut self, position: f32) -> Result<i32, Direction> {
        if position <= self.min_travel {
            Result::Err(Direction::Backward)
        } else if position >= self.max_travel {
            Result::Err(Direction::Forward)
        } else {
            self.current_step = (position * self.steps_per_millimeter as f32) as i32;
            Result::Ok(self.current_step)
        }
    }

    /// Set the current velocity in mm/min
    /// Returns a `Result::Ok` with the set microseconds per step if successful
    /// Retuens a `Result::Err` if the set speed is too fast to be able to step
    ///     The speed is not set in that case
    pub fn set_current_velocity(&mut self, velocity: f32) -> Result<u32, ()> {

        if velocity > 0.0 {
            self.set_current_direction(Direction::Forward);
            let microseconds_per_step =
                (60000000.0 / (velocity * self.steps_per_millimeter as f32)) as u32;

            if microseconds_per_step > PULSE_LENGTH {
                self.microseconds_per_step = microseconds_per_step;
                return Result::Ok(microseconds_per_step);
            } else {
                return Result::Err(());
            }

        } else if velocity < 0.0 {
            self.set_current_direction(Direction::Backward);
            let microseconds_per_step =
                (60000000.0 / (-velocity * self.steps_per_millimeter as f32)) as u32;

            if microseconds_per_step > PULSE_LENGTH {
                self.microseconds_per_step = microseconds_per_step;
                return Result::Ok(microseconds_per_step);
            } else {
                return Result::Err(());
            }

        } else {
            self.microseconds_per_step = 0;
            return Result::Ok(0);
        }
    }

    /// Set the current direction
    pub fn set_current_direction(&mut self, direction: Direction) {
        self.current_direction = direction;

        match direction {
            Direction::Forward => {
                //bindings::digitalWrite(self.direction_pin, bindings::HIGH as u8)
                self.hardware.digital_write(self.direction_pin, PinState::High);
            },
            Direction::Backward => {
                //bindings::digitalWrite(self.direction_pin, bindings::LOW as u8)
                self.hardware.digital_write(self.direction_pin, PinState::Low);
            },
        }
    }

    /// Update everything
    /// Returns a `Result::Ok` with the current step if successfull,
    /// returns a `Result::Err` with the limit that would be breached
    ///     if the stepper would go out of range
    pub fn update(&mut self) -> Result<i32, Direction> {

        //let now = unsafe { bindings::micros() };
        let now = self.hardware.now();

        // Check if needed to start next step
        if now - self.last_step > self.microseconds_per_step {

            match self.current_direction {
                Direction::Forward => {
                    if self.current_step == self.max_steps {
                        return Result::Err(Direction::Forward);
                    }
                }
                Direction::Backward => {
                    if self.current_step == self.min_steps {
                        return Result::Err(Direction::Backward);
                    }
                }
            }

            /*
            unsafe {
                bindings::digitalWrite(self.step_pin, bindings::HIGH as u8);
            }
            */

            self.hardware.digital_write(self.step_pin, PinState::High);

            self.mid_pulse = true;
            self.last_step = now;
        }

        // Check if needed to end step pulse
        if self.mid_pulse && now - self.last_step > PULSE_LENGTH {

            /*
            unsafe {
                bindings::digitalWrite(self.step_pin, bindings::LOW as u8);
            }
            */

            self.hardware.digital_write(self.step_pin, PinState::Low);

            self.current_step += self.current_direction as i32;
            self.mid_pulse = false;
            self.last_step = now;
        }

        Result::Ok(self.current_step)
    }
}
<commit_msg>StepperMotor uses StepperMotorConfig<commit_after>use core::ops::Not;
use core::fmt::Debug;

use hardware::HardwareGpio;
use hardware::HardwareTime;
use hardware::PinMode;
use hardware::PinState;

const PULSE_LENGTH: u32 = 100;

#[derive(Debug)]
pub struct StepRateError {}

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    Forward = 1,
    Backward = -1,
}

impl Not for Direction {
    type Output = Direction;

    fn not(self) -> Direction {
        match self {
            Direction::Forward => Direction::Backward,
            Direction::Backward => Direction::Forward,
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct StepperMotorConfig {
    /// The pin to step with
    step_pin: u8,

    /// The pin to use for direction
    direction_pin: u8,

    /// The max limit of the stepper
    min_travel: f32,

    /// The min limit of the stepper
    max_travel: f32,

    /// The steps per millimeter
    steps_per_millimeter: i32
}

#[derive(Debug)]
pub struct StepperMotor<'a, H: 'a> {
    /// The current step that the motor is at
    current_step: i32,

    /// The current direction
    current_direction: Direction,

    /// The current traveling velocity in microseconds per step
    microseconds_per_step: u32,

    /// The minimum number of steps that can be stepped
    min_steps: i32,

    /// The maxmimum number of steps that can be stepped
    max_steps: i32,

    /// The last time we stepped
    last_step: u32,

    /// If we are in the middle of a pulse
    mid_pulse: bool,

    /// The config to use
    config: StepperMotorConfig,

    /// The hardware to use to step the motor
    hardware: &'a mut H,
}

impl<'a, H: HardwareGpio + HardwareTime + Debug> StepperMotor<'a, H> {
    /// Make a new stepper motor
    pub fn new(
        config: StepperMotorConfig,
        hardware: &mut H,
    ) -> StepperMotor<H> {

        // Set the step and direction pins to output
        hardware.pin_mode(config.step_pin, PinMode::Output);
        hardware.pin_mode(config.direction_pin, PinMode::Output);

        StepperMotor {
            current_step: 0,
            current_direction: Direction::Backward,
            microseconds_per_step: 0,
            min_steps: (config.min_travel * config.steps_per_millimeter as f32) as i32,
            max_steps: (config.max_travel * config.steps_per_millimeter as f32) as i32,
            last_step: 0,
            mid_pulse: false,
            config: config,
            hardware: hardware,
        }
    }

    /// Get the max that this stepper can travel in mm
    pub fn get_max_travel(&self) -> f32 {
        self.config.max_travel
    }

    /// Get the min this stepper can travel in mm
    pub fn get_min_travel(&self) -> f32 {
        self.config.min_travel
    }

    /// Return the current position in mm
    pub fn get_current_position(&self) -> f32 {
        self.current_step as f32 / self.config.steps_per_millimeter as f32
    }

    /// Return the current velocity in mm/min
    pub fn get_current_velocity(&self) -> f32 {
        self.current_direction as i32 as f32 * 60000000.0 /
            (self.microseconds_per_step as i32 * self.config.steps_per_millimeter) as f32
    }

    /// Get the current direction
    pub fn get_current_direction(&self) -> Direction {
        self.current_direction
    }

    /// Set the max that this stepper can travel in mm
    pub fn set_max_travel(&mut self, max: f32) {
        self.config.max_travel = max;
        self.max_steps = (max * self.config.steps_per_millimeter as f32) as i32;
    }

    /// Set the min that this stepper can travel in mm
    pub fn set_min_travel(&mut self, min: f32) {
        self.config.min_travel = min;
        self.min_steps = (min * self.config.steps_per_millimeter as f32) as i32;
    }

    /// Set the current position (As in G92)
    /// Returns a `Result::Ok` with the now current step if successfull
    /// returns a `Result::Err` with the limit direction if the position is out of range
    pub fn set_current_position(&mut self, position: f32) -> Result<i32, Direction> {
        if position <= self.config.min_travel {
            Result::Err(Direction::Backward)
        } else if position >= self.config.max_travel {
            Result::Err(Direction::Forward)
        } else {
            self.current_step = (position * self.config.steps_per_millimeter as f32) as i32;
            Result::Ok(self.current_step)
        }
    }

    /// Set the current velocity in mm/min
    /// Returns a `Result::Ok` with the set microseconds per step if successful
    /// Retuens a `Result::Err` if the set speed is too fast to be able to step
    ///     The speed is not set in that case
    pub fn set_current_velocity(&mut self, velocity: f32) -> Result<u32, ()> {

        if velocity > 0.0 {
            self.set_current_direction(Direction::Forward);
            let microseconds_per_step =
                (60000000.0 / (velocity * self.config.steps_per_millimeter as f32)) as u32;

            if microseconds_per_step > PULSE_LENGTH {
                self.microseconds_per_step = microseconds_per_step;
                return Result::Ok(microseconds_per_step);
            } else {
                return Result::Err(());
            }

        } else if velocity < 0.0 {
            self.set_current_direction(Direction::Backward);
            let microseconds_per_step =
                (60000000.0 / (-velocity * self.config.steps_per_millimeter as f32)) as u32;

            if microseconds_per_step > PULSE_LENGTH {
                self.microseconds_per_step = microseconds_per_step;
                return Result::Ok(microseconds_per_step);
            } else {
                return Result::Err(());
            }

        } else {
            self.microseconds_per_step = 0;
            return Result::Ok(0);
        }
    }

    /// Set the current direction
    pub fn set_current_direction(&mut self, direction: Direction) {
        self.current_direction = direction;

        match direction {
            Direction::Forward => {
                //bindings::digitalWrite(self.direction_pin, bindings::HIGH as u8)
                self.hardware.digital_write(self.config.direction_pin, PinState::High);
            },
            Direction::Backward => {
                //bindings::digitalWrite(self.direction_pin, bindings::LOW as u8)
                self.hardware.digital_write(self.config.direction_pin, PinState::Low);
            },
        }
    }

    /// Update everything
    /// Returns a `Result::Ok` with the current step if successfull,
    /// returns a `Result::Err` with the limit that would be breached
    ///     if the stepper would go out of range
    pub fn update(&mut self) -> Result<i32, Direction> {

        //let now = unsafe { bindings::micros() };
        let now = self.hardware.now();

        // Check if needed to start next step
        if now - self.last_step > self.microseconds_per_step {

            match self.current_direction {
                Direction::Forward => {
                    if self.current_step == self.max_steps {
                        return Result::Err(Direction::Forward);
                    }
                }
                Direction::Backward => {
                    if self.current_step == self.min_steps {
                        return Result::Err(Direction::Backward);
                    }
                }
            }

            self.hardware.digital_write(self.config.step_pin, PinState::High);

            self.mid_pulse = true;
            self.last_step = now;
        }

        // Check if needed to end step pulse
        if self.mid_pulse && now - self.last_step > PULSE_LENGTH {

            self.hardware.digital_write(self.config.step_pin, PinState::Low);

            self.current_step += self.current_direction as i32;
            self.mid_pulse = false;
            self.last_step = now;
        }

        Result::Ok(self.current_step)
    }
}
<|endoftext|>


<commit_before>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use misc::walk_ty;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Warn,
    "Warn on `x = x + ..` where x is a `String`"
}

#[derive(Copy,Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprAssign(ref target, ref  src) =&e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "You assign the result of adding something to this string. \
                    Consider using `String::push_str(..) instead.")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
    if let TyStruct(def_id, _) = walk_ty(cx.tcx.expr_ty(e)).sty {
        match_def_path(cx, def_id, &["std", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<commit_msg>whitespace<commit_after>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use misc::walk_ty;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Warn,
    "Warn on `x = x + ..` where x is a `String`"
}

#[derive(Copy,Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprAssign(ref target, ref  src) = &e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "You assign the result of adding something to this string. \
                    Consider using `String::push_str(..) instead.")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
    if let TyStruct(def_id, _) = walk_ty(cx.tcx.expr_ty(e)).sty {
        match_def_path(cx, def_id, &["std", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<|endoftext|>


<commit_before>use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    DISABLED,
    NOW,
    CH1_PE,
    CH1_NE,
    CH2_PE,
    CH2_NE,
    EXT_PE,
    EXT_NE,
    AWG_PE,
    AWG_NE,
}

impl ::std::fmt::Display for Source {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Source::DISABLED => "DISABLED",
            &Source::NOW => "NOW",
            &Source::CH1_PE => "CH1_PE",
            &Source::CH1_NE => "CH1_NE",
            &Source::CH2_PE => "CH2_PE",
            &Source::CH2_NE => "CH2_NE",
            &Source::EXT_PE => "EXT_PE",
            &Source::EXT_NE => "EXT_NE",
            &Source::AWG_PE => "AWG_PE",
            &Source::AWG_NE => "AWG_NE",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    WAIT,
    TD,
    UNKNOW,
}

impl ::std::convert::From<String> for State {
    fn from(s: String) -> Self {
        match s.as_str() {
            "WAIT" => State::WAIT,
            "TD" => State::TD,
            _ => State::UNKNOW,
        }
    }
}

#[derive(Clone)]
pub struct Trigger {
    socket: ::std::cell::RefCell<Socket>,
}

impl Trigger {
    pub fn new(socket: Socket) -> Self {
        Trigger {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Trigger immediately or set trigger source & edge.
     */
    pub fn enable(&self, source: Source) {
        self.send(format!("ACQ:TRIG {}", source));
    }

    /**
     * Disable triggering.
     */
    pub fn disable(&self) {
        self.enable(Source::DISABLED);
    }

    /**
     *  Get trigger status.
     *
     *  If DISABLED -> TD else WAIT.
     */
    pub fn get_state(&self) -> State {
        self.send("ACQ:TRIG:STAT?");

        self.receive()
            .into()
    }

    /**
     * Set trigger delay in samples.
     */
    pub fn set_delay(&self, delay: u16) {
        self.send(format!("ACQ:TRIG:DLY {}", delay));
    }

    /**
     * Get trigger delay in samples.
     */
    pub fn get_delay(&self) -> u16 {
        self.send("ACQ:TRIG:DLY?");

        self.receive()
            .parse()
            .unwrap()
    }

    /**
     * Set trigger delay in ns.
     */
    pub fn set_delay_in_ns(&self, delay: u8) {
        self.send(format!("ACQ:TRIG:DLY:NS {}", delay));
    }

    /**
     * Get trigger delay in ns.
     */
    pub fn get_delay_in_ns(&self) -> String {
        self.send("ACQ:TRIG:DLY:NS?");

        self.receive()
    }

    /**
     * Set trigger level in mV.
     */
    pub fn set_level(&self, level: u8) {
        self.send(format!("ACQ:TRIG:LEV {}", level));
    }

    /**
     * Get trigger level in mV.
     */
    pub fn get_level(&self) -> String {
        self.send("ACQ:TRIG:LEV?");

        self.receive()
    }

    fn send<D>(&self, message: D)
        where D: ::std::fmt::Display
    {
        let mut socket = self.socket.borrow_mut();

        socket.send(message);
    }

    fn receive(&self) -> String {
        let mut socket = self.socket.borrow_mut();

        socket.receive()
    }
}

#[cfg(test)]
mod test {
    macro_rules! trigger_assert {
        ($f:ident, $e:expr) => {
            let (rx, trigger) = create_trigger();

            trigger.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_enable() {
        let (rx, trigger) = create_trigger();

        trigger.enable(::trigger::Source::NOW);
        assert_eq!("ACQ:TRIG NOW\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        trigger_assert!(disable, "ACQ:TRIG DISABLED\r\n");
    }

    #[test]
    fn test_get_state() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_state(), ::trigger::State::WAIT);
    }

    #[test]
    fn test_set_delay() {
        let (rx, trigger) = create_trigger();

        trigger.set_delay(0);
        assert_eq!("ACQ:TRIG:DLY 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_delay() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_delay(), 2314);
    }

    #[test]
    fn test_set_delay_in_ns() {
        let (rx, trigger) = create_trigger();

        trigger.set_delay_in_ns(0);
        assert_eq!("ACQ:TRIG:DLY:NS 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_delay_in_ns() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_delay_in_ns().as_str(), "128ns");
    }

    #[test]
    fn test_set_level() {
        let (rx, trigger) = create_trigger();

        trigger.set_level(0);
        assert_eq!("ACQ:TRIG:LEV 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_level() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_level().as_str(), "123mV");
    }

    fn create_trigger() -> (::std::sync::mpsc::Receiver<String>, ::trigger::Trigger) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::trigger::Trigger::new(socket))
    }
}
<commit_msg>[trigger] trigger::get_delay_in_ns() returns u8<commit_after>use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    DISABLED,
    NOW,
    CH1_PE,
    CH1_NE,
    CH2_PE,
    CH2_NE,
    EXT_PE,
    EXT_NE,
    AWG_PE,
    AWG_NE,
}

impl ::std::fmt::Display for Source {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Source::DISABLED => "DISABLED",
            &Source::NOW => "NOW",
            &Source::CH1_PE => "CH1_PE",
            &Source::CH1_NE => "CH1_NE",
            &Source::CH2_PE => "CH2_PE",
            &Source::CH2_NE => "CH2_NE",
            &Source::EXT_PE => "EXT_PE",
            &Source::EXT_NE => "EXT_NE",
            &Source::AWG_PE => "AWG_PE",
            &Source::AWG_NE => "AWG_NE",
        };

        write!(f, "{}", display)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    WAIT,
    TD,
    UNKNOW,
}

impl ::std::convert::From<String> for State {
    fn from(s: String) -> Self {
        match s.as_str() {
            "WAIT" => State::WAIT,
            "TD" => State::TD,
            _ => State::UNKNOW,
        }
    }
}

#[derive(Clone)]
pub struct Trigger {
    socket: ::std::cell::RefCell<Socket>,
}

impl Trigger {
    pub fn new(socket: Socket) -> Self {
        Trigger {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Trigger immediately or set trigger source & edge.
     */
    pub fn enable(&self, source: Source) {
        self.send(format!("ACQ:TRIG {}", source));
    }

    /**
     * Disable triggering.
     */
    pub fn disable(&self) {
        self.enable(Source::DISABLED);
    }

    /**
     *  Get trigger status.
     *
     *  If DISABLED -> TD else WAIT.
     */
    pub fn get_state(&self) -> State {
        self.send("ACQ:TRIG:STAT?");

        self.receive()
            .into()
    }

    /**
     * Set trigger delay in samples.
     */
    pub fn set_delay(&self, delay: u16) {
        self.send(format!("ACQ:TRIG:DLY {}", delay));
    }

    /**
     * Get trigger delay in samples.
     */
    pub fn get_delay(&self) -> u16 {
        self.send("ACQ:TRIG:DLY?");

        self.receive()
            .parse()
            .unwrap()
    }

    /**
     * Set trigger delay in ns.
     */
    pub fn set_delay_in_ns(&self, delay: u8) {
        self.send(format!("ACQ:TRIG:DLY:NS {}", delay));
    }

    /**
     * Get trigger delay in ns.
     */
    pub fn get_delay_in_ns(&self) -> u8 {
        self.send("ACQ:TRIG:DLY:NS?");

        self.receive()
            .replace("ns", "")
            .parse()
            .unwrap()
    }

    /**
     * Set trigger level in mV.
     */
    pub fn set_level(&self, level: u8) {
        self.send(format!("ACQ:TRIG:LEV {}", level));
    }

    /**
     * Get trigger level in mV.
     */
    pub fn get_level(&self) -> String {
        self.send("ACQ:TRIG:LEV?");

        self.receive()
    }

    fn send<D>(&self, message: D)
        where D: ::std::fmt::Display
    {
        let mut socket = self.socket.borrow_mut();

        socket.send(message);
    }

    fn receive(&self) -> String {
        let mut socket = self.socket.borrow_mut();

        socket.receive()
    }
}

#[cfg(test)]
mod test {
    macro_rules! trigger_assert {
        ($f:ident, $e:expr) => {
            let (rx, trigger) = create_trigger();

            trigger.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_enable() {
        let (rx, trigger) = create_trigger();

        trigger.enable(::trigger::Source::NOW);
        assert_eq!("ACQ:TRIG NOW\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        trigger_assert!(disable, "ACQ:TRIG DISABLED\r\n");
    }

    #[test]
    fn test_get_state() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_state(), ::trigger::State::WAIT);
    }

    #[test]
    fn test_set_delay() {
        let (rx, trigger) = create_trigger();

        trigger.set_delay(0);
        assert_eq!("ACQ:TRIG:DLY 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_delay() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_delay(), 2314);
    }

    #[test]
    fn test_set_delay_in_ns() {
        let (rx, trigger) = create_trigger();

        trigger.set_delay_in_ns(0);
        assert_eq!("ACQ:TRIG:DLY:NS 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_delay_in_ns() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_delay_in_ns(), 128);
    }

    #[test]
    fn test_set_level() {
        let (rx, trigger) = create_trigger();

        trigger.set_level(0);
        assert_eq!("ACQ:TRIG:LEV 0\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_level() {
        let (_, trigger) = create_trigger();

        assert_eq!(trigger.get_level().as_str(), "123mV");
    }

    fn create_trigger() -> (::std::sync::mpsc::Receiver<String>, ::trigger::Trigger) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::trigger::Trigger::new(socket))
    }
}
<|endoftext|>


<commit_before>/*
  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use std::path::Path;
use chrono::{DateTime,Utc};
use exempi::Xmp;

use plutils::Plist;
use store;
use custominfo::CustomInfoProperties;
use exif::ExifProperties;
use iptc::IptcProperties;
use AplibObject;
use AplibType;
use audit::{
    audit_get_str_value,
    audit_get_int_value,
    audit_get_bool_value,
    audit_get_dict_value,
    audit_get_date_value,
    audit_get_array_value,
    SkipReason,
    Report
};
use xmp::ToXmp;

/// A rendered image. There is one for the orignal, and one per
/// actual version. `Version` are associated to a `Master`.
pub struct Version {
    uuid: Option<String>,
    model_id: Option<i64>,
    /// The associated `Master`.
    master_uuid: Option<String>,

    /// uuid of the `Folder` project this reside in.
    pub project_uuid: Option<String>,
    /// uuid of the raw `Master`.
    pub raw_master_uuid: Option<String>,
    /// uuid of the non raw `Master`.
    pub nonraw_master_uuid: Option<String>,
    pub timezone_name: Option<String>,
    pub create_date: Option<DateTime<Utc>>,
    pub image_date: Option<DateTime<Utc>>,
    pub export_image_change_date: Option<DateTime<Utc>>,
    pub export_metadata_change_date: Option<DateTime<Utc>>,
    pub version_number: Option<i64>,
    pub db_version: Option<i64>,
    pub db_minor_version: Option<i64>,
    pub is_flagged: Option<bool>,
    /// Indicate the version is the original.
    pub is_original: Option<bool>,
    pub is_editable: Option<bool>,
    pub is_hidden: Option<bool>,
    pub is_in_trash: Option<bool>,
    pub file_name: Option<String>,
    pub name: Option<String>,
    pub rating: Option<i64>,
    pub rotation: Option<i64>,
    pub colour_label_index: Option<i64>,

    pub iptc: Option<IptcProperties>,
    pub exif: Option<ExifProperties>,
    pub custom_info: Option<CustomInfoProperties>,
    pub keywords: Option<Vec<Plist>>,
}

impl AplibObject for Version {
    /// Load the version object from the plist at plist_path.
    fn from_path(plist_path: &Path,
                 mut auditor: Option<&mut Report>) -> Option<Version> {

        use plutils::*;

        let plist = parse_plist(plist_path);
        match plist {
            Plist::Dictionary(ref dict) => {
                let iptc = audit_get_dict_value(dict, "iptcProperties",
                                                &mut auditor);
                let exif = audit_get_dict_value(dict, "exifProperties",
                                                &mut auditor);
                let custom_info = audit_get_dict_value(dict, "customInfo",
                                                       &mut auditor);
                let result = Some(Version {
                    uuid: audit_get_str_value(dict, "uuid", &mut auditor),
                    master_uuid: audit_get_str_value(
                        dict, "masterUuid", &mut auditor),
                    project_uuid: audit_get_str_value(
                        dict, "projectUuid", &mut auditor),
                    raw_master_uuid: audit_get_str_value(
                        dict, "rawMasterUuid", &mut auditor),
                    nonraw_master_uuid: audit_get_str_value(
                        dict, "nonRawMasterUuid", &mut auditor),
                    timezone_name: audit_get_str_value(
                        dict, "imageTimeZoneName", &mut auditor),
                    create_date: audit_get_date_value(
                        dict, "createDate", &mut auditor),
                    image_date: audit_get_date_value(
                        dict, "imageDate", &mut auditor),
                    export_image_change_date: audit_get_date_value(
                        dict, "exportImageChangeDate", &mut auditor),
                    export_metadata_change_date: audit_get_date_value(
                        dict, "exportMetadataChangeDate", &mut auditor),
                    version_number: audit_get_int_value(
                        dict, "versionNumber", &mut auditor),
                    db_version: audit_get_int_value(
                        dict, "version", &mut auditor),
                    db_minor_version: audit_get_int_value(
                        dict, "minorVersion", &mut auditor),
                    is_flagged: audit_get_bool_value(
                        dict, "isFlagged", &mut auditor),
                    is_original: audit_get_bool_value(
                        dict, "isOriginal", &mut auditor),
                    is_editable: audit_get_bool_value(
                        dict, "isEditable", &mut auditor),
                    is_hidden: audit_get_bool_value(
                        dict, "isHidden", &mut auditor),
                    is_in_trash: audit_get_bool_value(
                        dict, "isInTrash", &mut auditor),
                    file_name: audit_get_str_value(
                        dict, "fileName", &mut auditor),
                    name: audit_get_str_value(dict, "name", &mut auditor),
                    model_id: audit_get_int_value(
                        dict, "modelId", &mut auditor),
                    rating: audit_get_int_value(
                        dict, "mainRating", &mut auditor),
                    rotation: audit_get_int_value(
                        dict, "rotation", &mut auditor),
                    colour_label_index: audit_get_int_value(
                        dict, "colorLabelIndex", &mut auditor),
                    iptc: IptcProperties::from(&iptc, &mut auditor),
                    exif: ExifProperties::from(&exif, &mut auditor),
                    custom_info: CustomInfoProperties::from(
                        &custom_info, &mut auditor),
                    keywords: audit_get_array_value(
                        dict, "keywords", &mut auditor),
                });
                if auditor.is_some() {
                    let ref mut auditor = auditor.unwrap();
                    auditor.skip("statistics", SkipReason::Ignore);
                    auditor.skip("thumbnailGroup", SkipReason::Ignore);
                    auditor.skip("faceDetectionIsFromPreview",
                                 SkipReason::Ignore);
                    auditor.skip("processedHeight", SkipReason::Ignore);
                    auditor.skip("processedWidth", SkipReason::Ignore);
                    auditor.skip("masterHeight", SkipReason::Ignore);
                    auditor.skip("masterWidth", SkipReason::Ignore);
                    auditor.skip("supportedStatus", SkipReason::Ignore);
                    auditor.skip("showInLibrary", SkipReason::Ignore);

                    auditor.skip("adjustmentProperties", SkipReason::Ignore); // don't know what to do yet
                    auditor.skip("RKImageAdjustments", SkipReason::Ignore);
                    auditor.skip("hasAdjustments", SkipReason::Ignore);
                    auditor.skip("hasEnabledAdjustments", SkipReason::Ignore);
                    auditor.skip("renderVersion", SkipReason::Ignore);

                    auditor.skip("imageProxyState", SkipReason::Ignore);
                    auditor.skip("plistWriteTimestamp", SkipReason::Ignore);
                    auditor.audit_ignored(dict, None);
                }
                result
            },
            _ =>
                None
        }
    }
    fn obj_type(&self) -> AplibType {
        AplibType::Version
    }
    fn uuid(&self) -> &Option<String> {
        &self.uuid
    }
    fn parent(&self) -> &Option<String> {
        &self.master_uuid
    }
    fn model_id(&self) -> i64 {
        self.model_id.unwrap_or(0)
    }
    fn is_valid(&self) -> bool {
        self.uuid.is_some()
    }
    fn wrap(obj: Version) -> store::Wrapper {
        store::Wrapper::Version(Box::new(obj))
    }
}

impl ToXmp for Version {

    fn to_xmp(&self, xmp: &mut Xmp) -> bool {
        if let Some(ref iptc) = self.iptc {
            iptc.to_xmp(xmp);
        }
        true
    }
}

#[cfg(test)]
#[test]
fn test_version_parse() {
    use testutils;

    let version = Version::from_path(
        testutils::get_test_file_path("Version-0.apversion")
            .as_path(), None);
    assert!(version.is_some());
    let version = version.unwrap();

    assert_eq!(version.uuid.as_ref().unwrap(), "MHMIbw5CQaiMgQ3n7g2w2A");
    assert!(version.is_original.unwrap());
    assert_eq!(version.master_uuid.as_ref().unwrap(), "WZMCPPRHR%C3nffgeeS4IQ");
    assert_eq!(version.name.as_ref().unwrap(), "img_3136");
    assert!(version.iptc.is_some());
    let iptc = version.iptc.as_ref().unwrap();
    assert!(iptc.bag.contains_key("Byline"));
    assert!(iptc.bag.contains_key("CiAdrCity"));
    let exif = version.exif.as_ref().unwrap();
    assert!(exif.bag.contains_key("ApertureValue"));
    assert!(exif.bag.contains_key("Depth"))
    // XXX fix when have actual audit.
//    println!("report {:?}", report);
}
<commit_msg>version: test the Xmp from IPTC<commit_after>/*
  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use std::path::Path;
use chrono::{DateTime,Utc};
use exempi::Xmp;

use plutils::Plist;
use store;
use custominfo::CustomInfoProperties;
use exif::ExifProperties;
use iptc::IptcProperties;
use AplibObject;
use AplibType;
use audit::{
    audit_get_str_value,
    audit_get_int_value,
    audit_get_bool_value,
    audit_get_dict_value,
    audit_get_date_value,
    audit_get_array_value,
    SkipReason,
    Report
};
use xmp::ToXmp;

/// A rendered image. There is one for the orignal, and one per
/// actual version. `Version` are associated to a `Master`.
pub struct Version {
    uuid: Option<String>,
    model_id: Option<i64>,
    /// The associated `Master`.
    master_uuid: Option<String>,

    /// uuid of the `Folder` project this reside in.
    pub project_uuid: Option<String>,
    /// uuid of the raw `Master`.
    pub raw_master_uuid: Option<String>,
    /// uuid of the non raw `Master`.
    pub nonraw_master_uuid: Option<String>,
    pub timezone_name: Option<String>,
    pub create_date: Option<DateTime<Utc>>,
    pub image_date: Option<DateTime<Utc>>,
    pub export_image_change_date: Option<DateTime<Utc>>,
    pub export_metadata_change_date: Option<DateTime<Utc>>,
    pub version_number: Option<i64>,
    pub db_version: Option<i64>,
    pub db_minor_version: Option<i64>,
    pub is_flagged: Option<bool>,
    /// Indicate the version is the original.
    pub is_original: Option<bool>,
    pub is_editable: Option<bool>,
    pub is_hidden: Option<bool>,
    pub is_in_trash: Option<bool>,
    pub file_name: Option<String>,
    pub name: Option<String>,
    pub rating: Option<i64>,
    pub rotation: Option<i64>,
    pub colour_label_index: Option<i64>,

    pub iptc: Option<IptcProperties>,
    pub exif: Option<ExifProperties>,
    pub custom_info: Option<CustomInfoProperties>,
    pub keywords: Option<Vec<Plist>>,
}

impl AplibObject for Version {
    /// Load the version object from the plist at plist_path.
    fn from_path(plist_path: &Path,
                 mut auditor: Option<&mut Report>) -> Option<Version> {

        use plutils::*;

        let plist = parse_plist(plist_path);
        match plist {
            Plist::Dictionary(ref dict) => {
                let iptc = audit_get_dict_value(dict, "iptcProperties",
                                                &mut auditor);
                let exif = audit_get_dict_value(dict, "exifProperties",
                                                &mut auditor);
                let custom_info = audit_get_dict_value(dict, "customInfo",
                                                       &mut auditor);
                let result = Some(Version {
                    uuid: audit_get_str_value(dict, "uuid", &mut auditor),
                    master_uuid: audit_get_str_value(
                        dict, "masterUuid", &mut auditor),
                    project_uuid: audit_get_str_value(
                        dict, "projectUuid", &mut auditor),
                    raw_master_uuid: audit_get_str_value(
                        dict, "rawMasterUuid", &mut auditor),
                    nonraw_master_uuid: audit_get_str_value(
                        dict, "nonRawMasterUuid", &mut auditor),
                    timezone_name: audit_get_str_value(
                        dict, "imageTimeZoneName", &mut auditor),
                    create_date: audit_get_date_value(
                        dict, "createDate", &mut auditor),
                    image_date: audit_get_date_value(
                        dict, "imageDate", &mut auditor),
                    export_image_change_date: audit_get_date_value(
                        dict, "exportImageChangeDate", &mut auditor),
                    export_metadata_change_date: audit_get_date_value(
                        dict, "exportMetadataChangeDate", &mut auditor),
                    version_number: audit_get_int_value(
                        dict, "versionNumber", &mut auditor),
                    db_version: audit_get_int_value(
                        dict, "version", &mut auditor),
                    db_minor_version: audit_get_int_value(
                        dict, "minorVersion", &mut auditor),
                    is_flagged: audit_get_bool_value(
                        dict, "isFlagged", &mut auditor),
                    is_original: audit_get_bool_value(
                        dict, "isOriginal", &mut auditor),
                    is_editable: audit_get_bool_value(
                        dict, "isEditable", &mut auditor),
                    is_hidden: audit_get_bool_value(
                        dict, "isHidden", &mut auditor),
                    is_in_trash: audit_get_bool_value(
                        dict, "isInTrash", &mut auditor),
                    file_name: audit_get_str_value(
                        dict, "fileName", &mut auditor),
                    name: audit_get_str_value(dict, "name", &mut auditor),
                    model_id: audit_get_int_value(
                        dict, "modelId", &mut auditor),
                    rating: audit_get_int_value(
                        dict, "mainRating", &mut auditor),
                    rotation: audit_get_int_value(
                        dict, "rotation", &mut auditor),
                    colour_label_index: audit_get_int_value(
                        dict, "colorLabelIndex", &mut auditor),
                    iptc: IptcProperties::from(&iptc, &mut auditor),
                    exif: ExifProperties::from(&exif, &mut auditor),
                    custom_info: CustomInfoProperties::from(
                        &custom_info, &mut auditor),
                    keywords: audit_get_array_value(
                        dict, "keywords", &mut auditor),
                });
                if auditor.is_some() {
                    let ref mut auditor = auditor.unwrap();
                    auditor.skip("statistics", SkipReason::Ignore);
                    auditor.skip("thumbnailGroup", SkipReason::Ignore);
                    auditor.skip("faceDetectionIsFromPreview",
                                 SkipReason::Ignore);
                    auditor.skip("processedHeight", SkipReason::Ignore);
                    auditor.skip("processedWidth", SkipReason::Ignore);
                    auditor.skip("masterHeight", SkipReason::Ignore);
                    auditor.skip("masterWidth", SkipReason::Ignore);
                    auditor.skip("supportedStatus", SkipReason::Ignore);
                    auditor.skip("showInLibrary", SkipReason::Ignore);

                    auditor.skip("adjustmentProperties", SkipReason::Ignore); // don't know what to do yet
                    auditor.skip("RKImageAdjustments", SkipReason::Ignore);
                    auditor.skip("hasAdjustments", SkipReason::Ignore);
                    auditor.skip("hasEnabledAdjustments", SkipReason::Ignore);
                    auditor.skip("renderVersion", SkipReason::Ignore);

                    auditor.skip("imageProxyState", SkipReason::Ignore);
                    auditor.skip("plistWriteTimestamp", SkipReason::Ignore);
                    auditor.audit_ignored(dict, None);
                }
                result
            },
            _ =>
                None
        }
    }
    fn obj_type(&self) -> AplibType {
        AplibType::Version
    }
    fn uuid(&self) -> &Option<String> {
        &self.uuid
    }
    fn parent(&self) -> &Option<String> {
        &self.master_uuid
    }
    fn model_id(&self) -> i64 {
        self.model_id.unwrap_or(0)
    }
    fn is_valid(&self) -> bool {
        self.uuid.is_some()
    }
    fn wrap(obj: Version) -> store::Wrapper {
        store::Wrapper::Version(Box::new(obj))
    }
}

impl ToXmp for Version {

    fn to_xmp(&self, xmp: &mut Xmp) -> bool {
        if let Some(ref iptc) = self.iptc {
            iptc.to_xmp(xmp);
        }
        true
    }
}

#[cfg(test)]
#[test]
fn test_version_parse() {
    use testutils;
    use exempi;
    use xmp;

    let version = Version::from_path(
        testutils::get_test_file_path("Version-0.apversion")
            .as_path(), None);
    assert!(version.is_some());
    let version = version.unwrap();

    assert_eq!(version.uuid.as_ref().unwrap(), "MHMIbw5CQaiMgQ3n7g2w2A");
    assert!(version.is_original.unwrap());
    assert_eq!(version.master_uuid.as_ref().unwrap(), "WZMCPPRHR%C3nffgeeS4IQ");
    assert_eq!(version.name.as_ref().unwrap(), "img_3136");
    assert!(version.iptc.is_some());
    let iptc = version.iptc.as_ref().unwrap();
    assert!(iptc.bag.contains_key("Byline"));
    assert!(iptc.bag.contains_key("CiAdrCity"));
    let exif = version.exif.as_ref().unwrap();
    assert!(exif.bag.contains_key("ApertureValue"));
    assert!(exif.bag.contains_key("Depth"));
    // XXX fix when have actual audit.
    //    println!("report {:?}", report);

    exempi::init();

    let mut xmp = Xmp::new();

    let result = version.to_xmp(&mut xmp);
    assert!(result);

    let mut options: exempi::PropFlags = exempi::PROP_NONE;
    let value = xmp.get_property(xmp::ns::NS_DC, "creator", &mut options);
    assert!(value.is_some());
    assert_eq!(value.unwrap().to_str(), "Hubert Figuiere");
}
<|endoftext|>


<commit_before>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76%

    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;
    use std::ptr::null_mut;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::fileapi::CreateFile2;
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;

    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // ref: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfile2
        // Using `CreateFile2("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
        let console_out_name: Vec<u16> = OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect();
        let console_handle = CreateFile2(
            console_out_name.as_ptr(),
            winapi::um::winnt::GENERIC_READ | winapi::um::winnt::GENERIC_WRITE,
            winapi::um::winnt::FILE_SHARE_WRITE,
            winapi::um::fileapi::OPEN_EXISTING,
            null_mut(),
        );
        if console_handle == INVALID_HANDLE_VALUE
        {
            return Err(GetLastError());
        }

        // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        if 0 == GetConsoleMode(console_handle, &mut console_mode)
        {
            return Err(GetLastError());
        }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            if 0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
            {
                return Err(GetLastError());
            }
        }
    }

    return Ok(());
}
<commit_msg>refactor ~ load winapi constants into the `enable_ansi_support()` namespace<commit_after>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76%

    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;
    use std::ptr::null_mut;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::fileapi::{CreateFile2, OPEN_EXISTING};
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};

    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // ref: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfile2
        // Using `CreateFile2("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
        let console_out_name: Vec<u16> = OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect();
        let console_handle = CreateFile2(
            console_out_name.as_ptr(),
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_WRITE,
            OPEN_EXISTING,
            null_mut(),
        );
        if console_handle == INVALID_HANDLE_VALUE
        {
            return Err(GetLastError());
        }

        // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        if 0 == GetConsoleMode(console_handle, &mut console_mode)
        {
            return Err(GetLastError());
        }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            if 0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
            {
                return Err(GetLastError());
            }
        }
    }

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


<commit_before>use super::{Group, Key, Symbols};
use crate::pad::PadAdapter;
use std::io::{Result, Write};

pub trait ToXkb {
    fn write_xkb(&self, w: impl Write) -> Result<()>;
}

impl ToXkb for Symbols {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        writeln!(w, r#"default partial alphanumeric_keys"#)?;
        writeln!(w, r#"xkb_symbols "basic" {{"#)?;

        let mut inner = PadAdapter::wrap(&mut w);
        writeln!(&mut inner, r#"include "latin""#)?;
        writeln!(&mut inner)?;

        for group in &self.groups {
            group.write_xkb(&mut inner)?;
        }

        writeln!(w, r#"}}"#)?;
        writeln!(w)?;

        Ok(())
    }
}

impl ToXkb for Group {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        writeln!(w, r#"name[Group1] = "{}";"#, self.name)?;
        writeln!(w)?;

        let mut inner = PadAdapter::wrap(&mut w);
        for include in &self.leading_includes {
            writeln!(&mut inner, r#"include "{}""#, include)?;
        }
        if !self.leading_includes.is_empty() {
            writeln!(w)?;
        }

        let mut inner = PadAdapter::wrap(&mut w);
        for key in &self.keys {
            key.write_xkb(&mut inner)?;
        }

        let mut inner = PadAdapter::wrap(&mut w);
        for include in &self.trailing_includes {
            writeln!(&mut inner, r#"include "{}""#, include)?;
        }

        Ok(())
    }
}

impl ToXkb for Key {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        write!(w, "key <{}> {{[ ", self.iso_code)?;

        /// Since modifiers are ordered, we need to make sure we don't continue
        /// emitting them when the previous one was empty.
        fn collect_keys(key: &Key, mut w: impl Write) -> Result<()> {
            if let Some(k) = &key.default {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.shift {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.alt {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.alt_shift {
                write!(w, "{}", k)?;
            } else {
                return Ok(());
            }
            Ok(())
        }

        collect_keys(self, &mut w)?;

        write!(w, " ]}};")?;
        writeln!(w)?;

        Ok(())
    }
}
<commit_msg>Fix XKB key output<commit_after>use super::{Group, Key, Symbols};
use crate::pad::PadAdapter;
use std::io::{Result, Write};

pub trait ToXkb {
    fn write_xkb(&self, w: impl Write) -> Result<()>;
}

impl ToXkb for Symbols {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        writeln!(w, r#"default partial alphanumeric_keys"#)?;
        writeln!(w, r#"xkb_symbols "basic" {{"#)?;

        let mut inner = PadAdapter::wrap(&mut w);
        writeln!(&mut inner, r#"include "latin""#)?;
        writeln!(&mut inner)?;

        for group in &self.groups {
            group.write_xkb(&mut inner)?;
        }

        writeln!(w, r#"}}"#)?;
        writeln!(w)?;

        Ok(())
    }
}

impl ToXkb for Group {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        writeln!(w, r#"name[Group1] = "{}";"#, self.name)?;
        writeln!(w)?;

        let mut inner = PadAdapter::wrap(&mut w);
        for include in &self.leading_includes {
            writeln!(&mut inner, r#"include "{}""#, include)?;
        }
        if !self.leading_includes.is_empty() {
            writeln!(w)?;
        }

        let mut inner = PadAdapter::wrap(&mut w);
        for key in &self.keys {
            key.write_xkb(&mut inner)?;
        }

        let mut inner = PadAdapter::wrap(&mut w);
        for include in &self.trailing_includes {
            writeln!(&mut inner, r#"include "{}""#, include)?;
        }

        Ok(())
    }
}

impl ToXkb for Key {
    fn write_xkb(&self, mut w: impl Write) -> Result<()> {
        write!(w, "key <A{}> {{ [ ", self.iso_code)?;

        /// Since modifiers are ordered, we need to make sure we don't continue
        /// emitting them when the previous one was empty.
        fn collect_keys(key: &Key, mut w: impl Write) -> Result<()> {
            if let Some(k) = &key.default {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.shift {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.alt {
                write!(w, "{}, ", k)?;
            } else {
                return Ok(());
            }
            if let Some(k) = &key.alt_shift {
                write!(w, "{}", k)?;
            } else {
                return Ok(());
            }
            Ok(())
        }

        collect_keys(self, &mut w)?;

        write!(w, " ] }};")?;
        writeln!(w)?;

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


<commit_before>//! Generate a module with a custom `#[path=...]` for each of the files in our
//! libclang version-specific test expectations so that they get their layout
//! tests run. We need to do this because cargo doesn't automatically detect
//! tests subdirectories.

use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;

const LIBCLANG_VERSION_DIRS: &'static [&'static str] = &[
    "libclang-5",
    "libclang-9",
];

fn main() {
    println!("cargo:rerun-if-changed=build.rs");

    let mut test_string = String::new();

    for dir in LIBCLANG_VERSION_DIRS {
        let dir = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
            .join("tests")
            .join(dir);

        println!("cargo:rerun-if-changed={}", dir.display());

        for entry in fs::read_dir(dir).unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            let path = path.canonicalize().unwrap_or_else(|_| path.into());
            if path.extension().map(|e| e.to_string_lossy()) !=
                Some("rs".into())
            {
                continue;
            }

            println!("cargo:rerun-if-changed={}", path.display());

            let module_name: String = path
                .display()
                .to_string()
                .chars()
                .map(|c| match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' => c,
                    _ => '_',
                })
                .collect();

            test_string.push_str(&format!(
                r###"
#[path = "{}"]
mod {};
"###,
                path.display(),
                module_name,
            ));
        }
    }

    let out_path = Path::new(&env::var_os("OUT_DIR").unwrap())
        .join("libclang_version_specific_generated_tests.rs");
    let mut test_file = fs::File::create(out_path).unwrap();
    test_file.write_all(test_string.as_bytes()).unwrap();
}
<commit_msg>escape `\` in paths for tests modules<commit_after>//! Generate a module with a custom `#[path=...]` for each of the files in our
//! libclang version-specific test expectations so that they get their layout
//! tests run. We need to do this because cargo doesn't automatically detect
//! tests subdirectories.

use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;

const LIBCLANG_VERSION_DIRS: &'static [&'static str] = &[
    "libclang-5",
    "libclang-9",
];

fn main() {
    println!("cargo:rerun-if-changed=build.rs");

    let mut test_string = String::new();

    for dir in LIBCLANG_VERSION_DIRS {
        let dir = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
            .join("tests")
            .join(dir);

        println!("cargo:rerun-if-changed={}", dir.display());

        for entry in fs::read_dir(dir).unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            let path = path.canonicalize().unwrap_or_else(|_| path.into());
            if path.extension().map(|e| e.to_string_lossy()) !=
                Some("rs".into())
            {
                continue;
            }

            println!("cargo:rerun-if-changed={}", path.display());

            let module_name: String = path
                .display()
                .to_string()
                .chars()
                .map(|c| match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' => c,
                    _ => '_',
                })
                .collect();

            test_string.push_str(&format!(
                r###"
#[path = "{}"]
mod {};
"###,
                path.display().to_string().replace('\\', "\\\\"),
                module_name,
            ));
        }
    }

    let out_path = Path::new(&env::var_os("OUT_DIR").unwrap())
        .join("libclang_version_specific_generated_tests.rs");
    let mut test_file = fs::File::create(out_path).unwrap();
    test_file.write_all(test_string.as_bytes()).unwrap();
}
<|endoftext|>