<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::RingBuf;

use spaces::immix_space::ImmixSpace;
use spaces::large_object_space::LargeObjectSpace;
use gc_object::GCObjectRef;
use spaces::CollectionType;

pub struct RCCollector {
    old_root_buffer: RingBuf<GCObjectRef>,
    decrement_buffer: RingBuf<GCObjectRef>,
    modified_buffer: RingBuf<GCObjectRef>,
    perform_evac: bool,
}

impl RCCollector {
    pub fn new() -> RCCollector {
        return RCCollector {
            old_root_buffer: RingBuf::new(),
            decrement_buffer: RingBuf::new(),
            modified_buffer: RingBuf::new(),
            perform_evac: false,
        };
    }

    pub fn collect(&mut self, collection_type: &CollectionType,
                   roots: &[GCObjectRef], immix_space: &mut ImmixSpace,
                   large_object_space: &mut LargeObjectSpace) {
        debug!("Start RC collection");
        self.perform_evac = collection_type.is_evac();
        self.process_old_roots();
        self.process_current_roots(immix_space, roots);
        self.process_los_new_objects(immix_space, large_object_space.get_new_objects());
        self.process_mod_buffer(immix_space);
        self.process_decrement_buffer(immix_space, large_object_space);
        debug!("Complete collection");
    }

    pub fn write_barrier(&mut self, object: GCObjectRef) {
        debug!("Write barrier on object {:p}", object);
        self.modified(object);
        for child in unsafe{ (*object).children() } {
            self.decrement(child);
        }
        unsafe{ (*object).set_logged(true); }
    }
}

impl RCCollector {
    fn modified(&mut self, object: GCObjectRef) {
        debug!("Push object {:p} into mod buffer", object);
        self.modified_buffer.push_back(object);
    }

    fn decrement(&mut self, object: GCObjectRef) {
        debug!("Push object {:p} into dec buffer", object);
        self.decrement_buffer.push_back(object);
    }

    fn increment(&mut self, immix_space: &mut ImmixSpace,
                 object: GCObjectRef, try_evacuate: bool) -> Option<GCObjectRef> {
        debug!("Increment object {:p}", object);
        if unsafe{ (*object).increment() } {
            if try_evacuate && self.perform_evac && immix_space.is_gc_object(object) {
                if let Some(new_object) = immix_space.maybe_evacuate(object) {
                    debug!("Evacuated object {:p} to {:p}", object, new_object);
                    immix_space.decrement_lines(object);
                    self.modified(new_object);
                    return Some(new_object);
                }
            }
            self.modified(object);
        }
        return None;
    }

    fn process_old_roots(&mut self) {
        debug!("Process old roots (size {})", self.old_root_buffer.len());
        self.decrement_buffer.extend(self.old_root_buffer.drain());
    }

    fn process_current_roots(&mut self, immix_space: &mut ImmixSpace,
                             roots: &[GCObjectRef]) {
        debug!("Process current roots (size {})", roots.len());
        for root in roots.iter().map(|o| *o) {
            debug!("Process root object: {:p}", root);
            self.increment(immix_space, root, false);
            self.old_root_buffer.push_back(root);
        }
    }

    fn process_los_new_objects(&mut self, immix_space: &mut ImmixSpace,
                               new_objects: RingBuf<GCObjectRef>) {
        debug!("Process los new_objects (size {})", new_objects.len());
        for object in new_objects {
            self.increment(immix_space, object, false);
            self.decrement(object);
        }
    }

    fn process_mod_buffer(&mut self, immix_space: &mut ImmixSpace) {
        debug!("Process mod buffer (size {})", self.modified_buffer.len());
        while let Some(object) = self.modified_buffer.pop_front() {
            debug!("Process object {:p} in mod buffer", object);
            unsafe { (*object).set_logged(false); }
            if immix_space.is_gc_object(object) {
                immix_space.set_gc_object(object);
                immix_space.increment_lines(object);
            }
            let children = unsafe{ (*object).children() };
            for (num, child) in children.into_iter().enumerate() {
                if let Some(new_child) = unsafe{ (*child).is_forwarded() } {
                    debug!("Child {:p} is forwarded to {:p}", child, new_child);
                    unsafe{ (*object).set_member(num, new_child); }
                    self.increment(immix_space, child, false);
                } else {
                    if let Some(new_child) = self.increment(immix_space,
                                                            child, true) {
                        unsafe{ (*object).set_member(num, new_child); }
                    }
                }
            }
        }
    }

    fn process_decrement_buffer(&mut self, immix_space: &mut ImmixSpace,
                                large_object_space: &mut LargeObjectSpace) {
        debug!("Process dec buffer (size {})", self.decrement_buffer.len());
        while let Some(object) =  self.decrement_buffer.pop_front() {
            debug!("Process object {:p} in dec buffer", object);
            if unsafe{ (*object).decrement() && !(*object).is_pinned() }  {
                for child in unsafe{ (*object).children() } {
                    self.decrement(child);
                }
                if immix_space.is_gc_object(object) {
                    immix_space.decrement_lines(object);
                    immix_space.unset_gc_object(object);
                    valgrind_freelike!(object);
                } else if large_object_space.is_gc_object(object) {
                    large_object_space.enqueue_free(object);
                }
            }
        }
    }
}
<commit_msg>Add rustdoc for rc_collector.rs<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::RingBuf;

use spaces::immix_space::ImmixSpace;
use spaces::large_object_space::LargeObjectSpace;
use gc_object::GCObjectRef;
use spaces::CollectionType;

/// The `RCCollector` perform the steps for the deferred coalesced
/// conservative reference counting. The `write_barrier()` must be called
/// before an objects members are changed. The `collect()` function should be
/// called periodically to incrementally collect garbage.
pub struct RCCollector {
    /// The roots of the last collection.
    ///
    /// At the start of a reference counting collection a decrement is
    /// enqueued for every old root.
    old_root_buffer: RingBuf<GCObjectRef>,

    /// The enqueued decrements on objects.
    ///
    /// These are applied in the last step of the reference counting
    /// collection.
    decrement_buffer: RingBuf<GCObjectRef>,

    /// A buffer of modified objects.
    ///
    /// Objects are pushed into this buffer if they are encountered for the
    /// first time by the reference counting collector or marked as modified
    /// using the `write_barrier()`.
    modified_buffer: RingBuf<GCObjectRef>,

    /// Flag if this collection is a evacuating collection.
    perform_evac: bool,
}

impl RCCollector {
    /// Create a new `RCCollector`.
    pub fn new() -> RCCollector {
        return RCCollector {
            old_root_buffer: RingBuf::new(),
            decrement_buffer: RingBuf::new(),
            modified_buffer: RingBuf::new(),
            perform_evac: false,
        };
    }

    /// Collect garbage using deferred coalesced conservative reference
    /// counting.
    ///
    /// The steps are:
    /// - process_old_roots()
    /// - process_current_roots()
    /// - process_los_new_objects()
    /// - process_mod_buffer()
    /// - process_decrement_buffer()
    pub fn collect(&mut self, collection_type: &CollectionType,
                   roots: &[GCObjectRef], immix_space: &mut ImmixSpace,
                   large_object_space: &mut LargeObjectSpace) {
        debug!("Start RC collection");
        self.perform_evac = collection_type.is_evac();
        self.process_old_roots();
        self.process_current_roots(immix_space, roots);
        self.process_los_new_objects(immix_space, large_object_space.get_new_objects());
        self.process_mod_buffer(immix_space);
        self.process_decrement_buffer(immix_space, large_object_space);
        debug!("Complete collection");
    }

    /// The write barrier for an object in deferred coalesced reference
    /// counting pushes the object into the modified buffer and enqueues a
    /// decrement for the old children.
    pub fn write_barrier(&mut self, object: GCObjectRef) {
        debug!("Write barrier on object {:p}", object);
        self.modified(object);
        for child in unsafe{ (*object).children() } {
            self.decrement(child);
        }
        unsafe{ (*object).set_logged(true); }
    }
}

impl RCCollector {
    /// Push an object into the modified buffer.
    fn modified(&mut self, object: GCObjectRef) {
        debug!("Push object {:p} into mod buffer", object);
        self.modified_buffer.push_back(object);
    }

    /// Enqueue a decrement for an object.
    fn decrement(&mut self, object: GCObjectRef) {
        debug!("Push object {:p} into dec buffer", object);
        self.decrement_buffer.push_back(object);
    }

    /// Perform an increment for an object.
    ///
    /// If this is the first time the reference counting collector encounters
    /// this object, it will be pushed into the modified buffer.
    ///
    /// If `try_evacuate` is set, the object is new an in the immix space and
    /// the collectors performs an opportunistic evacuation, this function
    /// tries to evacuate the object into a free block.
    fn increment(&mut self, immix_space: &mut ImmixSpace,
                 object: GCObjectRef, try_evacuate: bool) -> Option<GCObjectRef> {
        debug!("Increment object {:p}", object);
        if unsafe{ (*object).increment() } {
            if try_evacuate && self.perform_evac && immix_space.is_gc_object(object) {
                if let Some(new_object) = immix_space.maybe_evacuate(object) {
                    debug!("Evacuated object {:p} to {:p}", object, new_object);
                    immix_space.decrement_lines(object);
                    self.modified(new_object);
                    return Some(new_object);
                }
            }
            self.modified(object);
        }
        return None;
    }

    /// The old roots are enqueued for a decrement.
    fn process_old_roots(&mut self) {
        debug!("Process old roots (size {})", self.old_root_buffer.len());
        self.decrement_buffer.extend(self.old_root_buffer.drain());
    }

    /// The current roots are incremented (but never evacuated) and stored as
    /// old roots.
    fn process_current_roots(&mut self, immix_space: &mut ImmixSpace,
                             roots: &[GCObjectRef]) {
        debug!("Process current roots (size {})", roots.len());
        for root in roots.iter().map(|o| *o) {
            debug!("Process root object: {:p}", root);
            self.increment(immix_space, root, false);
            self.old_root_buffer.push_back(root);
        }
    }

    /// Objects (roots) in the large object space are temporarily incremented.
    fn process_los_new_objects(&mut self, immix_space: &mut ImmixSpace,
                               new_objects: RingBuf<GCObjectRef>) {
        debug!("Process los new_objects (size {})", new_objects.len());
        for object in new_objects {
            self.increment(immix_space, object, false);
            self.decrement(object);
        }
    }

    /// For deferred coalesced reference counting every remembered object will
    /// be processed to increment (and potentially evacuate) the members.
    fn process_mod_buffer(&mut self, immix_space: &mut ImmixSpace) {
        debug!("Process mod buffer (size {})", self.modified_buffer.len());
        while let Some(object) = self.modified_buffer.pop_front() {
            debug!("Process object {:p} in mod buffer", object);
            unsafe { (*object).set_logged(false); }
            if immix_space.is_gc_object(object) {
                immix_space.set_gc_object(object);
                immix_space.increment_lines(object);
            }
            let children = unsafe{ (*object).children() };
            for (num, child) in children.into_iter().enumerate() {
                if let Some(new_child) = unsafe{ (*child).is_forwarded() } {
                    debug!("Child {:p} is forwarded to {:p}", child, new_child);
                    unsafe{ (*object).set_member(num, new_child); }
                    self.increment(immix_space, child, false);
                } else {
                    if let Some(new_child) = self.increment(immix_space,
                                                            child, true) {
                        unsafe{ (*object).set_member(num, new_child); }
                    }
                }
            }
        }
    }

    /// The enqueued decrements are applied.
    ///
    /// If the reference counter drops to zero the memory is reclaimed and the
    /// members are enqueued for a decrement.
    fn process_decrement_buffer(&mut self, immix_space: &mut ImmixSpace,
                                large_object_space: &mut LargeObjectSpace) {
        debug!("Process dec buffer (size {})", self.decrement_buffer.len());
        while let Some(object) =  self.decrement_buffer.pop_front() {
            debug!("Process object {:p} in dec buffer", object);
            if unsafe{ (*object).decrement() && !(*object).is_pinned() }  {
                for child in unsafe{ (*object).children() } {
                    self.decrement(child);
                }
                if immix_space.is_gc_object(object) {
                    immix_space.decrement_lines(object);
                    immix_space.unset_gc_object(object);
                    valgrind_freelike!(object);
                } else if large_object_space.is_gc_object(object) {
                    large_object_space.enqueue_free(object);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Output borrows generally must have an input value from which it can borrow. The exception is
// the static lifetime.
fn output_only<'a>() -> (&'static u8, &'static u8) {
    static X: u8 = 8;
    static Y: u8 = 9;

    (&X, &Y)
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(output_only(), (&8, &9));

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - When we say "'a", we are talking about a scope in the calling environment.
// - Question: Why can't Rust ensure/infer/elide the struct scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<commit_msg>Added comment about terseness<commit_after>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Output borrows generally must have an input value from which it can borrow. The exception is
// the static lifetime.
// Couldn't Rust infer from the body of the function that the borrows are from the static lifetime?
//   - I feel that Rust favours explicitness over terseness. A functions behaviour should be
//   encoded directly into it's signature.
fn output_only<'a>() -> (&'static u8, &'static u8) {
    static X: u8 = 8;
    static Y: u8 = 9;

    (&X, &Y)
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

fn multi_lifetimes<'a, 'b>(a: &'a u8, b: &'b u8) -> bool {
    (a + b) > 10
}

fn multiple_lifetimes() -> bool {
    let a = &9;

    {
        let b = &9;

        multi_lifetimes(a, b)
    }
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(output_only(), (&8, &9));

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert!(multiple_lifetimes());

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Nor are you telling Rust to "allow" a binding to be available in a given named scope/lifetime.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - When we say "'a", we are talking about a scope in the calling environment.
// - Question: Why can't Rust ensure/infer/elide the struct scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<|endoftext|>


<commit_before>use std::str::FromStr;

/// A TIS-100 port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
    Any,
    Last,
}

/// An error which can be returned when parsing a port.
#[derive(Debug, PartialEq)]
pub struct ParsePortError;

impl FromStr for Port {
    type Err = ParsePortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            "ANY" => Ok(Port::Any),
            "LAST" => Ok(Port::Last),
            _ => Err(ParsePortError)
        }
    }
}

/// A TIS-100 register.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    Acc,
    Bak,
    Nil,
    Io(Port),
}

/// An error which can be returned when parsing a register.
#[derive(Debug, PartialEq)]
pub struct ParseRegisterError;

impl FromStr for Register {
    type Err = ParseRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ACC" => Ok(Register::Acc),
            "BAK" => Ok(Register::Bak),
            "NIL" => Ok(Register::Nil),
            _ => {
                if let Ok(port) = str::parse::<Port>(s) {
                    Ok(Register::Io(port))
                } else {
                    Err(ParseRegisterError)
                }
            }
        }
    }
}

/// The operand component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Operand {
    Val(isize),
    Reg(Register),
}

/// An error which can be returned when parsing an operand.
#[derive(Debug, PartialEq)]
pub struct ParseOperandError;

impl FromStr for Operand {
    type Err = ParseOperandError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(val) = str::parse::<isize>(s) {
            Ok(Operand::Val(val))
        } else if let Ok(register) = str::parse::<Register>(s) {
            Ok(Operand::Reg(register))
        } else {
            Err(ParseOperandError)
        }
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

/// A valid TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Nop,
    Mov(Operand, Register),
    Swp,
    Sav,
    Add(Operand),
    Sub(Operand),
    Neg,
    Jmp(usize),
    Jez(usize),
    Jnz(usize),
    Jgz(usize),
    Jlz(usize),
    Jro(Operand),
}

/// The list of instructions created by parsing the program source code. The
/// instructions can then be evaluated by a basic execution node.
pub type Program = Vec<Instruction>;

#[test]
fn test_parse_port() {
    assert_eq!(str::parse::<Port>("UP"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("up"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("DOWN"), Ok(Port::Down));
    assert_eq!(str::parse::<Port>("LEFT"), Ok(Port::Left));
    assert_eq!(str::parse::<Port>("RIGHT"), Ok(Port::Right));
    assert_eq!(str::parse::<Port>("ANY"), Ok(Port::Any));
    assert_eq!(str::parse::<Port>("LAST"), Ok(Port::Last));
    assert_eq!(str::parse::<Port>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_register() {
    assert_eq!(str::parse::<Register>("ACC"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("acc"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("BAK"), Ok(Register::Bak));
    assert_eq!(str::parse::<Register>("NIl"), Ok(Register::Nil));
    assert_eq!(str::parse::<Register>("UP"), Ok(Register::Io(Port::Up)));
    assert_eq!(str::parse::<Register>("bad"), Err(ParseRegisterError));
}

#[test]
fn test_parse_operand() {
    assert_eq!(str::parse::<Operand>("ACC"), Ok(Operand::Reg(Register::Acc)));
    assert_eq!(str::parse::<Operand>("1"), Ok(Operand::Val(1)));
    assert_eq!(str::parse::<Operand>("bad"), Err(ParseOperandError));
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<commit_msg>Break apart ports and pseudo-ports<commit_after>use std::str::FromStr;

/// A TIS-100 port.
#[derive(Debug, PartialEq, Copy, Clone, Hash)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
}

/// An error which can be returned when parsing a port.
#[derive(Debug, PartialEq)]
pub struct ParsePortError;

impl FromStr for Port {
    type Err = ParsePortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            _ => Err(ParsePortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PseudoPort {
    Any,
    Last,
}

/// An error which can be returned when parsing a psedo-port.
#[derive(Debug, PartialEq)]
pub struct ParsePseudoPortError;

impl FromStr for PseudoPort {
    type Err = ParsePseudoPortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ANY" => Ok(PseudoPort::Any),
            "LAST" => Ok(PseudoPort::Last),
            _ => Err(ParsePseudoPortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum IoRegister {
    Port(Port),
    Pseudo(PseudoPort),
}

/// An error which can be returned when parsing an IO register.
#[derive(Debug, PartialEq)]
pub struct ParseIoRegisterError;

impl FromStr for IoRegister {
    type Err = ParseIoRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(port) = str::parse::<Port>(s) {
            Ok(IoRegister::Port(port))
        } else if let Ok(pseudo) = str::parse::<PseudoPort>(s) {
            Ok(IoRegister::Pseudo(pseudo))
        } else {
            Err(ParseIoRegisterError)
        }
    }
}

/// A TIS-100 register.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    Acc,
    Bak,
    Nil,
    Io(IoRegister),
}

/// An error which can be returned when parsing a register.
#[derive(Debug, PartialEq)]
pub struct ParseRegisterError;

impl FromStr for Register {
    type Err = ParseRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ACC" => Ok(Register::Acc),
            "BAK" => Ok(Register::Bak),
            "NIL" => Ok(Register::Nil),
            _ => {
                if let Ok(reg) = str::parse::<IoRegister>(s) {
                    Ok(Register::Io(reg))
                } else {
                    Err(ParseRegisterError)
                }
            }
        }
    }
}

/// The operand component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Operand {
    Val(isize),
    Reg(Register),
}

/// An error which can be returned when parsing an operand.
#[derive(Debug, PartialEq)]
pub struct ParseOperandError;

impl FromStr for Operand {
    type Err = ParseOperandError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(val) = str::parse::<isize>(s) {
            Ok(Operand::Val(val))
        } else if let Ok(register) = str::parse::<Register>(s) {
            Ok(Operand::Reg(register))
        } else {
            Err(ParseOperandError)
        }
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

/// A valid TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Nop,
    Mov(Operand, Register),
    Swp,
    Sav,
    Add(Operand),
    Sub(Operand),
    Neg,
    Jmp(usize),
    Jez(usize),
    Jnz(usize),
    Jgz(usize),
    Jlz(usize),
    Jro(Operand),
}

/// The list of instructions created by parsing the program source code. The
/// instructions can then be evaluated by a basic execution node.
pub type Program = Vec<Instruction>;

#[test]
fn test_parse_port() {
    assert_eq!(str::parse::<Port>("UP"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("up"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("DOWN"), Ok(Port::Down));
    assert_eq!(str::parse::<Port>("LEFT"), Ok(Port::Left));
    assert_eq!(str::parse::<Port>("RIGHT"), Ok(Port::Right));
    assert_eq!(str::parse::<Port>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_psedo_port() {
    assert_eq!(str::parse::<PseudoPort>("ANY"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("any"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("LAST"), Ok(PseudoPort::Last));
    assert_eq!(str::parse::<PseudoPort>("bad"), Err(ParsePseudoPortError));
}

#[test]
fn test_parse_io_register() {
    assert_eq!(str::parse::<IoRegister>("UP"), Ok(IoRegister::Port(Port::Up)));
    assert_eq!(str::parse::<IoRegister>("ANY"), Ok(IoRegister::Pseudo(PseudoPort::Any)));
    assert_eq!(str::parse::<IoRegister>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_register() {
    assert_eq!(str::parse::<Register>("ACC"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("acc"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("BAK"), Ok(Register::Bak));
    assert_eq!(str::parse::<Register>("NIl"), Ok(Register::Nil));
    assert_eq!(str::parse::<Register>("UP"), Ok(Register::Io(IoRegister::Port(Port::Up))));
    assert_eq!(str::parse::<Register>("bad"), Err(ParseRegisterError));
}

#[test]
fn test_parse_operand() {
    assert_eq!(str::parse::<Operand>("ACC"), Ok(Operand::Reg(Register::Acc)));
    assert_eq!(str::parse::<Operand>("1"), Ok(Operand::Val(1)));
    assert_eq!(str::parse::<Operand>("bad"), Err(ParseOperandError));
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<|endoftext|>


<commit_before>use element::Element;
use element::Feature;
use loc::Loc;
use settings::Settings;
use element::Stroke;

pub struct Optimizer {
    elements: Vec<Vec<Vec<Element>>>,
    consumed_loc: Vec<Loc>,
}

impl Optimizer {
    pub fn new(elements: Vec<Vec<Vec<Element>>>, consumed_loc: Vec<Loc>) -> Optimizer {
        Optimizer {
            elements: elements,
            consumed_loc: consumed_loc,
        }
    }

    fn get(&self, loc: &Loc) -> Option<&Vec<Element>> {
        match self.elements.get(loc.y as usize) {
            Some(row) => row.get(loc.x as usize),
            None => None,
        }
    }

    // return the reduced element and the index of the matching element on this location
    fn reduce(&self, elm1: &Element, loc2: &Loc) -> Option<(Vec<Element>, usize)> {
        // try all the elments of this location
        if let Some(elements2) = self.get(loc2){
            if elements2.len() > 0 {
                for (i,elm2) in elements2.iter().enumerate(){
                    // use the element that can be reduced with
                    if let Some(reduced) = elm1.reduce(&elm2){
                        let mut new_reduced = vec![];
                        new_reduced.push(reduced);
                        new_reduced.sort();
                        new_reduced.dedup();
                        return Some((new_reduced, i));
                    }
                }
            }
        }
        None

    }
    /// trace the and try to reduce this element against the elements
    /// at this location(loc),
    /// returns the reduced element, the location and index of the consumed element
    fn trace_elements(&self, element: &Element, loc: &Loc) -> (Vec<Element>, Vec<(Loc, usize)>) {
        //trace to the right first
        let right = loc.right();
        let bottom = loc.bottom();
        let bottom_right = loc.bottom_right();
        let bottom_left = loc.bottom_left();
        if let Some((all_reduced, elm_index)) = self.reduce(element, &right){
            let mut all_consumed:Vec<(Loc, usize)> = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &right);
                all_consumed.push((right.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom);
                all_consumed.push((bottom.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom_right){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom_right);
                all_consumed.push((bottom_right.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom_left){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom_left);
                all_consumed.push((bottom_left.clone(),elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else{
            (vec![element.to_owned()], vec![])
        }
    }

    // TODO: order the elements in such a way that
    // the start -> end -> start chains nicely
    pub fn optimize(&self, settings: &Settings) -> Vec<Element> {
        let mut completely_consumed_locs:Vec<Loc> = self.consumed_loc.clone();
        let mut tracing_consumed_locs: Vec<(Loc,usize)> = vec![];
        let mut optimized = vec![];
        for (y, line) in self.elements.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                let loc = &Loc::new(x as i32, y as i32);
                if !completely_consumed_locs.contains(loc) {
                    for (elm_index, elm) in cell.iter().enumerate() {
                        if !tracing_consumed_locs.contains(&(loc.clone(),elm_index)){
                            let (traced, consumed) = self.trace_elements(elm, loc);
                            optimized.extend(traced);
                            tracing_consumed_locs.extend(consumed);
                        }
                    }
                }
            }
        }
        //let excess = self.get_excess_elements(&completely_consumed_locs, &tracing_consumed_locs);
        //optimized.extend(excess);
        optimized.sort();
        optimized.dedup();
        if settings.compact_path {
            self.merge_paths(optimized)
        } else {
            optimized
        }
    }

    fn get_excess_elements(&self, complete_consumed: &Vec<Loc>, decimated: &Vec<(Loc,usize)>) -> Vec<Element> {
        let mut excess = vec![];
        for (y, line) in self.elements.iter().enumerate(){
            for (x, cell) in line.iter().enumerate(){
                let loc = &Loc::new(x as i32, y as i32);
                if !complete_consumed.contains(loc){
                    for (elm_index, elm) in cell.iter().enumerate(){
                        if !decimated.contains(&(loc.clone(), elm_index)){
                            // this one is consumed
                        }
                        else{
                            excess.push(elm.clone());
                        }
                    }
                }
            }
        }
        excess
    }
    // take all paths and non-arrow line in 1 path
    // the text in separated
    fn merge_paths(&self, elements: Vec<Element>) -> Vec<Element> {
        let mut merged = vec![];
        let mut solid_lines = vec![];
        let mut dashed_lines = vec![];
        let mut solid_arcs = vec![];
        let mut dashed_arcs = vec![];
        let mut arrows = vec![];
        let mut text = vec![];
        let mut circles = vec![];
        for elm in elements {
            match elm {
                Element::Circle(_, _, _) => {
                    circles.push(elm.clone());
                }
                Element::Line(_, _, ref stroke, ref features) => {
                    for feature in features{
                        match *feature {
                            Feature::Arrow => {
                                arrows.push(elm.clone());
                            }
                            Feature::ArrowStart => {
                                arrows.push(elm.clone());
                            }
                            // circle at the end rather than arrow
                            Feature::Circle => {
                                arrows.push(elm.clone());
                            }
                        }
                    }
                    match *stroke {
                        Stroke::Solid => {
                            solid_lines.push(elm.clone());
                        }
                        Stroke::Dashed => {
                            dashed_lines.push(elm.clone());
                        }
                    }
                },
                Element::Arc(_, _, _, _, _, ref stroke, ref features) => {
                    for feature in features{
                        match *feature {
                            Feature::Arrow => {
                                arrows.push(elm.clone());
                            }
                            Feature::ArrowStart => {
                                arrows.push(elm.clone());
                            }
                            Feature::Circle => {
                                arrows.push(elm.clone());
                            }
                        }
                    }

                    match *stroke {
                        Stroke::Solid => {
                            solid_arcs.push(elm.clone());
                        }
                        Stroke::Dashed => {
                            dashed_arcs.push(elm.clone());
                        }
                    }
                },
                Element::Text(_, _) => text.push(elm.clone()),
            }
        }
        merged.extend(solid_lines);
        merged.extend(dashed_lines);
        merged.extend(solid_arcs);
        merged.extend(dashed_arcs);
        merged.extend(arrows);
        merged.extend(text);
        merged.extend(circles);
        merged
    }
}

<commit_msg>Prevent from re-adding the elements when there are multiple features involved<commit_after>use element::Element;
use element::Feature;
use loc::Loc;
use settings::Settings;
use element::Stroke;

pub struct Optimizer {
    elements: Vec<Vec<Vec<Element>>>,
    consumed_loc: Vec<Loc>,
}

impl Optimizer {
    pub fn new(elements: Vec<Vec<Vec<Element>>>, consumed_loc: Vec<Loc>) -> Optimizer {
        Optimizer {
            elements: elements,
            consumed_loc: consumed_loc,
        }
    }

    fn get(&self, loc: &Loc) -> Option<&Vec<Element>> {
        match self.elements.get(loc.y as usize) {
            Some(row) => row.get(loc.x as usize),
            None => None,
        }
    }

    // return the reduced element and the index of the matching element on this location
    fn reduce(&self, elm1: &Element, loc2: &Loc) -> Option<(Vec<Element>, usize)> {
        // try all the elments of this location
        if let Some(elements2) = self.get(loc2){
            if elements2.len() > 0 {
                for (i,elm2) in elements2.iter().enumerate(){
                    // use the element that can be reduced with
                    if let Some(reduced) = elm1.reduce(&elm2){
                        let mut new_reduced = vec![];
                        new_reduced.push(reduced);
                        new_reduced.sort();
                        new_reduced.dedup();
                        return Some((new_reduced, i));
                    }
                }
            }
        }
        None

    }
    /// trace the and try to reduce this element against the elements
    /// at this location(loc),
    /// returns the reduced element, the location and index of the consumed element
    fn trace_elements(&self, element: &Element, loc: &Loc) -> (Vec<Element>, Vec<(Loc, usize)>) {
        //trace to the right first
        let right = loc.right();
        let bottom = loc.bottom();
        let bottom_right = loc.bottom_right();
        let bottom_left = loc.bottom_left();
        if let Some((all_reduced, elm_index)) = self.reduce(element, &right){
            let mut all_consumed:Vec<(Loc, usize)> = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &right);
                all_consumed.push((right.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom);
                all_consumed.push((bottom.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom_right){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom_right);
                all_consumed.push((bottom_right.clone(), elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else if let Some((all_reduced, elm_index)) = self.reduce(element, &bottom_left){
            let mut all_consumed = vec![];
            let mut only_reduced = vec![];
            for reduced_elm in all_reduced{
                let (reduced, consumed) = self.trace_elements(&reduced_elm, &bottom_left);
                all_consumed.push((bottom_left.clone(),elm_index));
                all_consumed.extend(consumed);
                only_reduced = reduced;
            }
            (only_reduced, all_consumed)
        }
        else{
            (vec![element.to_owned()], vec![])
        }
    }

    // TODO: order the elements in such a way that
    // the start -> end -> start chains nicely
    pub fn optimize(&self, settings: &Settings) -> Vec<Element> {
        let mut completely_consumed_locs:Vec<Loc> = self.consumed_loc.clone();
        let mut tracing_consumed_locs: Vec<(Loc,usize)> = vec![];
        let mut optimized = vec![];
        for (y, line) in self.elements.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                let loc = &Loc::new(x as i32, y as i32);
                if !completely_consumed_locs.contains(loc) {
                    for (elm_index, elm) in cell.iter().enumerate() {
                        if !tracing_consumed_locs.contains(&(loc.clone(),elm_index)){
                            let (traced, consumed) = self.trace_elements(elm, loc);
                            optimized.extend(traced);
                            tracing_consumed_locs.extend(consumed);
                        }
                    }
                }
            }
        }
        //let excess = self.get_excess_elements(&completely_consumed_locs, &tracing_consumed_locs);
        //optimized.extend(excess);
        optimized.sort();
        optimized.dedup();
        if settings.compact_path {
            self.merge_paths(optimized)
        } else {
            optimized
        }
    }

    fn get_excess_elements(&self, complete_consumed: &Vec<Loc>, decimated: &Vec<(Loc,usize)>) -> Vec<Element> {
        let mut excess = vec![];
        for (y, line) in self.elements.iter().enumerate(){
            for (x, cell) in line.iter().enumerate(){
                let loc = &Loc::new(x as i32, y as i32);
                if !complete_consumed.contains(loc){
                    for (elm_index, elm) in cell.iter().enumerate(){
                        if !decimated.contains(&(loc.clone(), elm_index)){
                            // this one is consumed
                        }
                        else{
                            excess.push(elm.clone());
                        }
                    }
                }
            }
        }
        excess
    }
    // take all paths and non-arrow line in 1 path
    // the text in separated
    fn merge_paths(&self, elements: Vec<Element>) -> Vec<Element> {
        let mut merged = vec![];
        let mut solid_lines = vec![];
        let mut dashed_lines = vec![];
        let mut solid_arcs = vec![];
        let mut dashed_arcs = vec![];
        let mut text = vec![];
        let mut circles = vec![];
        for elm in elements {
            match elm {
                Element::Circle(_, _, _) => {
                    circles.push(elm.clone());
                }
                Element::Line(_, _, ref stroke, ref features) => {
                    match *stroke {
                        Stroke::Solid => {
                            solid_lines.push(elm.clone());
                        }
                        Stroke::Dashed => {
                            dashed_lines.push(elm.clone());
                        }
                    }
                },
                Element::Arc(_, _, _, _, _, ref stroke, ref features) => {

                    match *stroke {
                        Stroke::Solid => {
                            solid_arcs.push(elm.clone());
                        }
                        Stroke::Dashed => {
                            dashed_arcs.push(elm.clone());
                        }
                    }
                },
                Element::Text(_, _) => text.push(elm.clone()),
            }
        }
        merged.extend(solid_lines);
        merged.extend(dashed_lines);
        merged.extend(solid_arcs);
        merged.extend(dashed_arcs);
        merged.extend(text);
        merged.extend(circles);
        merged
    }
}

<|endoftext|>


<commit_before>//! Installs rust-analyzer language server and/or editor plugin.

use std::{env, path::PathBuf, str};

use anyhow::{Context, Result};

use crate::cmd::{run, run_with_output, Cmd};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 41;

pub struct InstallCmd {
    pub client: Option<ClientOpt>,
    pub server: Option<ServerOpt>,
}

pub enum ClientOpt {
    VsCode,
}

pub struct ServerOpt {
    pub jemalloc: bool,
}

impl InstallCmd {
    pub fn run(self) -> Result<()> {
        let both = self.server.is_some() && self.client.is_some();
        if cfg!(target_os = "macos") {
            fix_path_for_mac().context("Fix path for mac")?
        }
        if let Some(server) = self.server {
            install_server(server).context("install server")?;
        }
        if let Some(client) = self.client {
            install_client(client).context("install client")?;
        }
        if both {
            eprintln!(
                "
    Installation complete.

    Add `\"rust-analyzer.raLspServerPath\": \"ra_lsp_server\",` to VS Code settings,
    otherwise it will use the latest release from GitHub.
"
            )
        }
        Ok(())
    }
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => anyhow::bail!("Failed getting HOME from environment with error: {}.", e),
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => anyhow::bail!("Could not get PATH variable from env."),
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths).context("build env PATH")?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    let npm_version = Cmd {
        unix: r"npm --version",
        windows: r"cmd.exe /c npm --version",
        work_dir: "./editors/code",
    }
    .run();

    if npm_version.is_err() {
        eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
    }

    Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" }
        .run()?;
    Cmd {
        unix: r"npm run package --scripts-prepend-node-path",
        windows: r"cmd.exe /c npm run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium", "code-oss"].iter().find(|bin| {
        Cmd {
            unix: &format!("{} --version", bin),
            windows: &format!("cmd.exe /c {}.cmd --version", bin),
            work_dir: "./editors/code",
        }
        .run()
        .is_ok()
    });

    let code_binary = match code_binary {
        Some(it) => it,
        None => anyhow::bail!("Can't execute `code --version`. Perhaps it is not in $PATH?"),
    };

    Cmd {
        unix: &format!(r"{} --install-extension ./rust-analyzer-0.1.0.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./rust-analyzer-0.1.0.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let installed_extensions = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !installed_extensions.contains("rust-analyzer") {
        anyhow::bail!(
            "Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again."
        );
    }

    if installed_extensions.contains("ra-lsp") {
        Cmd {
            unix: &format!(r"{} --uninstall-extension matklad.ra-lsp", code_binary),
            windows: &format!(
                r"cmd.exe /c {}.cmd --uninstall-extension matklad.ra-lsp",
                code_binary
            ),
            work_dir: "./editors/code",
        }
        .run()?;
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(stdout) = run_with_output("cargo --version", ".") {
        println!("{}", stdout);
        if !check_version(&stdout, REQUIRED_RUST_VERSION) {
            old_rust = true;
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<commit_msg>Minor<commit_after>//! Installs rust-analyzer language server and/or editor plugin.

use std::{env, path::PathBuf, str};

use anyhow::{bail, format_err, Context, Result};

use crate::cmd::{run, run_with_output, Cmd};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 41;

pub struct InstallCmd {
    pub client: Option<ClientOpt>,
    pub server: Option<ServerOpt>,
}

pub enum ClientOpt {
    VsCode,
}

pub struct ServerOpt {
    pub jemalloc: bool,
}

impl InstallCmd {
    pub fn run(self) -> Result<()> {
        let both = self.server.is_some() && self.client.is_some();
        if cfg!(target_os = "macos") {
            fix_path_for_mac().context("Fix path for mac")?
        }
        if let Some(server) = self.server {
            install_server(server).context("install server")?;
        }
        if let Some(client) = self.client {
            install_client(client).context("install client")?;
        }
        if both {
            eprintln!(
                "
    Installation complete.

    Add `\"rust-analyzer.raLspServerPath\": \"ra_lsp_server\",` to VS Code settings,
    otherwise it will use the latest release from GitHub.
"
            )
        }
        Ok(())
    }
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => bail!("Could not get PATH variable from env."),
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths).context("build env PATH")?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    let npm_version = Cmd {
        unix: r"npm --version",
        windows: r"cmd.exe /c npm --version",
        work_dir: "./editors/code",
    }
    .run();

    if npm_version.is_err() {
        bail!("`npm --version` failed, `npm` is required to build the VS Code plugin")
    }

    Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" }
        .run()?;
    Cmd {
        unix: r"npm run package --scripts-prepend-node-path",
        windows: r"cmd.exe /c npm run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium", "code-oss"]
        .iter()
        .find(|bin| {
            Cmd {
                unix: &format!("{} --version", bin),
                windows: &format!("cmd.exe /c {}.cmd --version", bin),
                work_dir: "./editors/code",
            }
            .run()
            .is_ok()
        })
        .ok_or_else(|| {
            format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
        })?;

    Cmd {
        unix: &format!(r"{} --install-extension ./rust-analyzer-0.1.0.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./rust-analyzer-0.1.0.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let installed_extensions = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !installed_extensions.contains("rust-analyzer") {
        bail!(
            "Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again."
        );
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(stdout) = run_with_output("cargo --version", ".") {
        println!("{}", stdout);
        if !check_version(&stdout, REQUIRED_RUST_VERSION) {
            old_rust = true;
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use boxed::Box;
use convert::Into;
use error;
use fmt;
use marker::{Send, Sync};
use option::Option::{self, Some, None};
use result;
use sys;

/// A specialized [`Result`][result] type for I/O operations.
///
/// [result]: ../result/enum.Result.html
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `Result`.
///
/// While usual Rust style is to import types directly, aliases of `Result`
/// often are not, to make it easier to distinguish between them. `Result` is
/// generally assumed to be `std::result::Result`, and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
/// of `std::result::Result`.
///
/// # Examples
///
/// A convenience function that bubbles an `io::Result` to its caller:
///
/// ```
/// use std::io;
///
/// fn get_string() -> io::Result<String> {
///     let mut buffer = String::new();
///
///     try!(io::stdin().read_line(&mut buffer));
///
///     Ok(buffer)
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;

/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
    repr: Repr,
}

enum Repr {
    Os(i32),
    Custom(Box<Custom>),
}

#[derive(Debug)]
struct Custom {
    kind: ErrorKind,
    error: Box<error::Error+Send+Sync>,
}

/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum ErrorKind {
    /// An entity was not found, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotFound,
    /// The operation lacked the necessary privileges to complete.
    #[stable(feature = "rust1", since = "1.0.0")]
    PermissionDenied,
    /// The connection was refused by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionRefused,
    /// The connection was reset by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionReset,
    /// The connection was aborted (terminated) by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionAborted,
    /// The network operation failed because it was not connected yet.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotConnected,
    /// A socket address could not be bound because the address is already in
    /// use elsewhere.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrInUse,
    /// A nonexistent interface was requested or the requested address was not
    /// local.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrNotAvailable,
    /// The operation failed because a pipe was closed.
    #[stable(feature = "rust1", since = "1.0.0")]
    BrokenPipe,
    /// An entity already exists, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    AlreadyExists,
    /// The operation needs to block to complete, but the blocking operation was
    /// requested to not occur.
    #[stable(feature = "rust1", since = "1.0.0")]
    WouldBlock,
    /// A parameter was incorrect.
    #[stable(feature = "rust1", since = "1.0.0")]
    InvalidInput,
    /// Data not valid for the operation were encountered.
    ///
    /// Unlike `InvalidInput`, this typically means that the operation
    /// parameters were valid, however the error was caused by malformed
    /// input data.
    #[stable(feature = "io_invalid_data", since = "1.2.0")]
    InvalidData,
    /// The I/O operation's timeout expired, causing it to be canceled.
    #[stable(feature = "rust1", since = "1.0.0")]
    TimedOut,
    /// An error returned when an operation could not be completed because a
    /// call to `write` returned `Ok(0)`.
    ///
    /// This typically means that an operation could only succeed if it wrote a
    /// particular number of bytes but only a smaller number of bytes could be
    /// written.
    #[stable(feature = "rust1", since = "1.0.0")]
    WriteZero,
    /// This operation was interrupted.
    ///
    /// Interrupted operations can typically be retried.
    #[stable(feature = "rust1", since = "1.0.0")]
    Interrupted,
    /// Any I/O error not part of this list.
    #[stable(feature = "rust1", since = "1.0.0")]
    Other,

    /// Any I/O error not part of this list.
    #[unstable(feature = "io_error_internals",
               reason = "better expressed through extensible enums that this \
                         enum cannot be exhaustively matched against",
               issue = "0")]
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Error {
    /// Creates a new I/O error from a known kind of error as well as an
    /// arbitrary error payload.
    ///
    /// This function is used to generically create I/O errors which do not
    /// originate from the OS itself. The `error` argument is an arbitrary
    /// payload which will be contained in this `Error`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Error, ErrorKind};
    ///
    /// // errors can be created from strings
    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
    ///
    /// // errors can also be created from other errors
    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
        where E: Into<Box<error::Error+Send+Sync>>
    {
        Error {
            repr: Repr::Custom(Box::new(Custom {
                kind: kind,
                error: error.into(),
            }))
        }
    }

    /// Returns an error representing the last OS error which occurred.
    ///
    /// This function reads the value of `errno` for the target platform (e.g.
    /// `GetLastError` on Windows) and will return a corresponding instance of
    /// `Error` for the error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn last_os_error() -> Error {
        Error::from_raw_os_error(sys::os::errno() as i32)
    }

    /// Creates a new instance of an `Error` from a particular OS error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn from_raw_os_error(code: i32) -> Error {
        Error { repr: Repr::Os(code) }
    }

    /// Returns the OS error that this error represents (if any).
    ///
    /// If this `Error` was constructed via `last_os_error` or
    /// `from_raw_os_error`, then this function will return `Some`, otherwise
    /// it will return `None`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn raw_os_error(&self) -> Option<i32> {
        match self.repr {
            Repr::Os(i) => Some(i),
            Repr::Custom(..) => None,
        }
    }

    /// Returns a reference to the inner error wrapped by this error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => Some(&*c.error),
        }
    }

    /// Returns a mutable reference to the inner error wrapped by this error
    /// (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref mut c) => Some(&mut *c.error),
        }
    }

    /// Consumes the `Error`, returning its inner error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(c) => Some(c.error)
        }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn kind(&self) -> ErrorKind {
        match self.repr {
            Repr::Os(code) => sys::decode_error_kind(code),
            Repr::Custom(ref c) => c.kind,
        }
    }
}

impl fmt::Debug for Repr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Repr::Os(ref code) =>
                fmt.debug_struct("Os").field("code", code)
                   .field("message", &sys::os::error_string(*code)).finish(),
            &Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) => "os error",
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }
}

fn _assert_error_is_sync_send() {
    fn _is_sync_send<T: Sync+Send>() {}
    _is_sync_send::<Error>();
}

#[cfg(test)]
mod test {
    use prelude::v1::*;
    use super::{Error, ErrorKind};
    use error;
    use error::Error as error_Error;
    use fmt;
    use sys::os::error_string;

    #[test]
    fn test_debug_error() {
        let code = 6;
        let msg = error_string(code);
        let err = Error { repr: super::Repr::Os(code) };
        let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
        assert_eq!(format!("{:?}", err), expected);
    }

    #[test]
    fn test_downcasting() {
        #[derive(Debug)]
        struct TestError;

        impl fmt::Display for TestError {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                Ok(())
            }
        }

        impl error::Error for TestError {
            fn description(&self) -> &str {
                "asdf"
            }
        }

        // we have to call all of these UFCS style right now since method
        // resolution won't implicitly drop the Send+Sync bounds
        let mut err = Error::new(ErrorKind::Other, TestError);
        assert!(err.get_ref().unwrap().is::<TestError>());
        assert_eq!("asdf", err.get_ref().unwrap().description());
        assert!(err.get_mut().unwrap().is::<TestError>());
        let extracted = err.into_inner().unwrap();
        extracted.downcast::<TestError>().unwrap();
    }
}
<commit_msg>Auto merge of #27885 - steveklabnik:gh27637, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use boxed::Box;
use convert::Into;
use error;
use fmt;
use marker::{Send, Sync};
use option::Option::{self, Some, None};
use result;
use sys;

/// A specialized [`Result`][result] type for I/O operations.
///
/// [result]: ../result/enum.Result.html
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `Result`.
///
/// While usual Rust style is to import types directly, aliases of `Result`
/// often are not, to make it easier to distinguish between them. `Result` is
/// generally assumed to be `std::result::Result`, and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
/// of `std::result::Result`.
///
/// # Examples
///
/// A convenience function that bubbles an `io::Result` to its caller:
///
/// ```
/// use std::io;
///
/// fn get_string() -> io::Result<String> {
///     let mut buffer = String::new();
///
///     try!(io::stdin().read_line(&mut buffer));
///
///     Ok(buffer)
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;

/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
    repr: Repr,
}

enum Repr {
    Os(i32),
    Custom(Box<Custom>),
}

#[derive(Debug)]
struct Custom {
    kind: ErrorKind,
    error: Box<error::Error+Send+Sync>,
}

/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum ErrorKind {
    /// An entity was not found, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotFound,
    /// The operation lacked the necessary privileges to complete.
    #[stable(feature = "rust1", since = "1.0.0")]
    PermissionDenied,
    /// The connection was refused by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionRefused,
    /// The connection was reset by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionReset,
    /// The connection was aborted (terminated) by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionAborted,
    /// The network operation failed because it was not connected yet.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotConnected,
    /// A socket address could not be bound because the address is already in
    /// use elsewhere.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrInUse,
    /// A nonexistent interface was requested or the requested address was not
    /// local.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrNotAvailable,
    /// The operation failed because a pipe was closed.
    #[stable(feature = "rust1", since = "1.0.0")]
    BrokenPipe,
    /// An entity already exists, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    AlreadyExists,
    /// The operation needs to block to complete, but the blocking operation was
    /// requested to not occur.
    #[stable(feature = "rust1", since = "1.0.0")]
    WouldBlock,
    /// A parameter was incorrect.
    #[stable(feature = "rust1", since = "1.0.0")]
    InvalidInput,
    /// Data not valid for the operation were encountered.
    ///
    /// Unlike `InvalidInput`, this typically means that the operation
    /// parameters were valid, however the error was caused by malformed
    /// input data.
    ///
    /// For example, a function that reads a file into a string will error with
    /// `InvalidData` if the file's contents are not valid UTF-8.
    #[stable(feature = "io_invalid_data", since = "1.2.0")]
    InvalidData,
    /// The I/O operation's timeout expired, causing it to be canceled.
    #[stable(feature = "rust1", since = "1.0.0")]
    TimedOut,
    /// An error returned when an operation could not be completed because a
    /// call to `write` returned `Ok(0)`.
    ///
    /// This typically means that an operation could only succeed if it wrote a
    /// particular number of bytes but only a smaller number of bytes could be
    /// written.
    #[stable(feature = "rust1", since = "1.0.0")]
    WriteZero,
    /// This operation was interrupted.
    ///
    /// Interrupted operations can typically be retried.
    #[stable(feature = "rust1", since = "1.0.0")]
    Interrupted,
    /// Any I/O error not part of this list.
    #[stable(feature = "rust1", since = "1.0.0")]
    Other,

    /// Any I/O error not part of this list.
    #[unstable(feature = "io_error_internals",
               reason = "better expressed through extensible enums that this \
                         enum cannot be exhaustively matched against",
               issue = "0")]
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Error {
    /// Creates a new I/O error from a known kind of error as well as an
    /// arbitrary error payload.
    ///
    /// This function is used to generically create I/O errors which do not
    /// originate from the OS itself. The `error` argument is an arbitrary
    /// payload which will be contained in this `Error`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Error, ErrorKind};
    ///
    /// // errors can be created from strings
    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
    ///
    /// // errors can also be created from other errors
    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
        where E: Into<Box<error::Error+Send+Sync>>
    {
        Error {
            repr: Repr::Custom(Box::new(Custom {
                kind: kind,
                error: error.into(),
            }))
        }
    }

    /// Returns an error representing the last OS error which occurred.
    ///
    /// This function reads the value of `errno` for the target platform (e.g.
    /// `GetLastError` on Windows) and will return a corresponding instance of
    /// `Error` for the error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn last_os_error() -> Error {
        Error::from_raw_os_error(sys::os::errno() as i32)
    }

    /// Creates a new instance of an `Error` from a particular OS error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn from_raw_os_error(code: i32) -> Error {
        Error { repr: Repr::Os(code) }
    }

    /// Returns the OS error that this error represents (if any).
    ///
    /// If this `Error` was constructed via `last_os_error` or
    /// `from_raw_os_error`, then this function will return `Some`, otherwise
    /// it will return `None`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn raw_os_error(&self) -> Option<i32> {
        match self.repr {
            Repr::Os(i) => Some(i),
            Repr::Custom(..) => None,
        }
    }

    /// Returns a reference to the inner error wrapped by this error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => Some(&*c.error),
        }
    }

    /// Returns a mutable reference to the inner error wrapped by this error
    /// (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref mut c) => Some(&mut *c.error),
        }
    }

    /// Consumes the `Error`, returning its inner error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[stable(feature = "io_error_inner", since = "1.3.0")]
    pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(c) => Some(c.error)
        }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn kind(&self) -> ErrorKind {
        match self.repr {
            Repr::Os(code) => sys::decode_error_kind(code),
            Repr::Custom(ref c) => c.kind,
        }
    }
}

impl fmt::Debug for Repr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Repr::Os(ref code) =>
                fmt.debug_struct("Os").field("code", code)
                   .field("message", &sys::os::error_string(*code)).finish(),
            &Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) => "os error",
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }
}

fn _assert_error_is_sync_send() {
    fn _is_sync_send<T: Sync+Send>() {}
    _is_sync_send::<Error>();
}

#[cfg(test)]
mod test {
    use prelude::v1::*;
    use super::{Error, ErrorKind};
    use error;
    use error::Error as error_Error;
    use fmt;
    use sys::os::error_string;

    #[test]
    fn test_debug_error() {
        let code = 6;
        let msg = error_string(code);
        let err = Error { repr: super::Repr::Os(code) };
        let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
        assert_eq!(format!("{:?}", err), expected);
    }

    #[test]
    fn test_downcasting() {
        #[derive(Debug)]
        struct TestError;

        impl fmt::Display for TestError {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                Ok(())
            }
        }

        impl error::Error for TestError {
            fn description(&self) -> &str {
                "asdf"
            }
        }

        // we have to call all of these UFCS style right now since method
        // resolution won't implicitly drop the Send+Sync bounds
        let mut err = Error::new(ErrorKind::Other, TestError);
        assert!(err.get_ref().unwrap().is::<TestError>());
        assert_eq!("asdf", err.get_ref().unwrap().description());
        assert!(err.get_mut().unwrap().is::<TestError>());
        let extracted = err.into_inner().unwrap();
        extracted.downcast::<TestError>().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate num;

use self::num::complex::{Complex32, Complex64};
use attribute::Symmetry;
use matrix::{BlasMatrix};
use matrix_vector;
use pointer::CPtr;
use scalar::Scalar;
use vector::BlasVector;

pub trait Gemv {
    fn gemv(alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

macro_rules! gemv_impl(
    ($t: ty, $gemv_fn: ident) => (
        impl Gemv for $t {
            fn gemv(alpha: $t, a: &BlasMatrix<$t>, x: &BlasVector<$t>, beta: $t, y: &mut BlasVector<$t>){
                unsafe {
                    matrix_vector::ll::$gemv_fn(a.order(), a.transpose(),
                        a.rows(), a.cols(),
                        (&alpha).as_const(),
                        a.as_ptr().as_c_ptr(), a.lead_dim(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        (&beta).as_const(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

gemv_impl!(f32,       cblas_sgemv)
gemv_impl!(f64,       cblas_dgemv)
gemv_impl!(Complex32, cblas_cgemv)
gemv_impl!(Complex64, cblas_zgemv)

pub trait Symv {
    fn symv(symmetry: Symmetry, alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

pub trait Hemv {
    fn hemv(symmetry: Symmetry, alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

macro_rules! symv_impl(
    ($trait_name: ident, $fn_name: ident, $t: ty, $symv_fn: ident) => (
        impl $trait_name for $t {
            fn $fn_name(symmetry: Symmetry, alpha: $t, a: &BlasMatrix<$t>, x: &BlasVector<$t>, beta: $t, y: &mut BlasVector<$t>){
                unsafe {
                    matrix_vector::ll::$symv_fn(a.order(), symmetry,
                        a.rows(),
                        (&alpha).as_const(),
                        a.as_ptr().as_c_ptr(), a.lead_dim(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        (&beta).as_const(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

symv_impl!(Symv, symv, f32,       cblas_ssymv)
symv_impl!(Symv, symv, f64,       cblas_dsymv)
symv_impl!(Symv, symv, Complex32, cblas_csymv)
symv_impl!(Symv, symv, Complex64, cblas_zsymv)

symv_impl!(Hemv, hemv, Complex32, cblas_chemv)
symv_impl!(Hemv, hemv, Complex64, cblas_zhemv)

pub trait Ger {
    fn ger(alpha: Self, x: &BlasVector<Self>, y: &BlasVector<Self>, a: &mut BlasMatrix<Self>);
}

pub trait Gerc {
    fn gerc(alpha: Self, x: &BlasVector<Self>, y: &BlasVector<Self>, a: &mut BlasMatrix<Self>);
}

macro_rules! ger_impl(
    ($trait_name: ident, $fn_name: ident, $t: ty, $ger_fn: ident) => (
        impl $trait_name for $t {
            fn $fn_name(alpha: $t, x: &BlasVector<$t>, y: &BlasVector<$t>, a: &mut BlasMatrix<$t>) {
                unsafe {
                    matrix_vector::ll::$ger_fn(a.order(),
                        a.rows(), a.cols(),
                        (&alpha).as_const(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        y.as_ptr().as_c_ptr(), y.inc(),
                        a.as_mut_ptr().as_c_ptr(), a.lead_dim());
                }
            }
        }
    );
)

ger_impl!(Ger, ger, f32,       cblas_sger)
ger_impl!(Ger, ger, f64,       cblas_dger)
ger_impl!(Ger, ger, Complex32, cblas_cgeru)
ger_impl!(Ger, ger, Complex64, cblas_zgeru)

ger_impl!(Gerc, gerc, Complex32, cblas_cgerc)
ger_impl!(Gerc, gerc, Complex64, cblas_zgerc)
<commit_msg>Add Her trait<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate num;

use self::num::complex::{Complex, Complex32, Complex64};
use attribute::Symmetry;
use matrix::{BlasMatrix};
use matrix_vector;
use pointer::CPtr;
use scalar::Scalar;
use vector::BlasVector;

pub trait Gemv {
    fn gemv(alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

macro_rules! gemv_impl(
    ($t: ty, $gemv_fn: ident) => (
        impl Gemv for $t {
            fn gemv(alpha: $t, a: &BlasMatrix<$t>, x: &BlasVector<$t>, beta: $t, y: &mut BlasVector<$t>){
                unsafe {
                    matrix_vector::ll::$gemv_fn(a.order(), a.transpose(),
                        a.rows(), a.cols(),
                        (&alpha).as_const(),
                        a.as_ptr().as_c_ptr(), a.lead_dim(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        (&beta).as_const(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

gemv_impl!(f32,       cblas_sgemv)
gemv_impl!(f64,       cblas_dgemv)
gemv_impl!(Complex32, cblas_cgemv)
gemv_impl!(Complex64, cblas_zgemv)

pub trait Symv {
    fn symv(symmetry: Symmetry, alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

pub trait Hemv {
    fn hemv(symmetry: Symmetry, alpha: Self, a: &BlasMatrix<Self>, x: &BlasVector<Self>, beta: Self, y: &mut BlasVector<Self>);
}

macro_rules! symv_impl(
    ($trait_name: ident, $fn_name: ident, $t: ty, $symv_fn: ident) => (
        impl $trait_name for $t {
            fn $fn_name(symmetry: Symmetry, alpha: $t, a: &BlasMatrix<$t>, x: &BlasVector<$t>, beta: $t, y: &mut BlasVector<$t>){
                unsafe {
                    matrix_vector::ll::$symv_fn(a.order(), symmetry,
                        a.rows(),
                        (&alpha).as_const(),
                        a.as_ptr().as_c_ptr(), a.lead_dim(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        (&beta).as_const(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

symv_impl!(Symv, symv, f32,       cblas_ssymv)
symv_impl!(Symv, symv, f64,       cblas_dsymv)
symv_impl!(Symv, symv, Complex32, cblas_csymv)
symv_impl!(Symv, symv, Complex64, cblas_zsymv)

symv_impl!(Hemv, hemv, Complex32, cblas_chemv)
symv_impl!(Hemv, hemv, Complex64, cblas_zhemv)

pub trait Ger {
    fn ger(alpha: Self, x: &BlasVector<Self>, y: &BlasVector<Self>, a: &mut BlasMatrix<Self>);
}

pub trait Gerc {
    fn gerc(alpha: Self, x: &BlasVector<Self>, y: &BlasVector<Self>, a: &mut BlasMatrix<Self>);
}

macro_rules! ger_impl(
    ($trait_name: ident, $fn_name: ident, $t: ty, $ger_fn: ident) => (
        impl $trait_name for $t {
            fn $fn_name(alpha: $t, x: &BlasVector<$t>, y: &BlasVector<$t>, a: &mut BlasMatrix<$t>) {
                unsafe {
                    matrix_vector::ll::$ger_fn(a.order(),
                        a.rows(), a.cols(),
                        (&alpha).as_const(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        y.as_ptr().as_c_ptr(), y.inc(),
                        a.as_mut_ptr().as_c_ptr(), a.lead_dim());
                }
            }
        }
    );
)

ger_impl!(Ger, ger, f32,       cblas_sger)
ger_impl!(Ger, ger, f64,       cblas_dger)
ger_impl!(Ger, ger, Complex32, cblas_cgeru)
ger_impl!(Ger, ger, Complex64, cblas_zgeru)

ger_impl!(Gerc, gerc, Complex32, cblas_cgerc)
ger_impl!(Gerc, gerc, Complex64, cblas_zgerc)

pub trait Her {
    fn her(symmetry: Symmetry, alpha: Self, x: &BlasVector<Complex<Self>>, a: &mut BlasMatrix<Complex<Self>>);
}

macro_rules! her_impl(
    ($t: ty, $her_fn: ident) => (
        impl Her for $t {
            fn her(symmetry: Symmetry, alpha: $t, x: &BlasVector<Complex<$t>>, a: &mut BlasMatrix<Complex<$t>>) {
                unsafe {
                    matrix_vector::ll::$her_fn(a.order(), symmetry,
                        a.rows(),
                        alpha,
                        x.as_ptr().as_c_ptr(), x.inc(),
                        a.as_mut_ptr().as_c_ptr(), a.lead_dim());
                }
            }
        }
    );
)

her_impl!(f32, cblas_cher)
her_impl!(f64, cblas_zher)
<|endoftext|>