<commit_before>use memory::MemSegment;
use cpu::CPU;

pub struct Disassembler<'a> {
    pc: u16,
    cpu: &'a mut CPU,
    bytes: Vec<u8>,
}

struct PartialInstruction {
    pattern: String,
}

impl PartialInstruction {
    fn finish(self, instr: &str) -> String {
        self.pattern.replace("$$$", instr).clone()
    }
}

pub struct Instruction {
    pub bytes: Vec<u8>,
    pub str: String,
}

impl<'a> Disassembler<'a> {
    pub fn new(cpu: &'a mut CPU) -> Disassembler {
        Disassembler {
            pc: cpu.pc,
            cpu: cpu,
            bytes: vec![],
        }
    }

    // Addressing modes
    fn immediate(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ #${:02X}", self.read_incr_pc()) }
    }
    fn absolute(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ #${:04X} = {:02X}", arg, self.cpu.mem.read(arg)),
        }
    }
    fn absolute_x(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.x as u16);
        PartialInstruction {
            pattern: format!("$$$ #${:04X},X @ {:02X} = {:02X}",
                             arg,
                             self.cpu.x,
                             self.cpu.mem.read(target)),
        }
    }
    fn absolute_y(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.y as u16);
        PartialInstruction {
            pattern: format!("$$$ #${:04X},Y @ {:02X} = {:02X}",
                             arg,
                             self.cpu.y,
                             self.cpu.mem.read(target)),
        }
    }
    fn zero_page(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ ${:02X} = {:02X}", arg, self.cpu.mem.read(arg as u16)),
        }
    }
    fn zero_page_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.x);
        PartialInstruction {
            pattern: format!("$$$ #${:02X},X @ {:02X} = {:02X}",
                             arg,
                             self.cpu.x,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn zero_page_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.y);
        PartialInstruction {
            pattern: format!("$$$ #${:02X},Y @ {:02X} = {:02X}",
                             arg,
                             self.cpu.y,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn indirect_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let zp_idx = arg.wrapping_add(self.cpu.x);
        let ptr = self.cpu.mem.read_w(zp_idx as u16);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ ({:02X},X) @ {:02X} = {:04X} = {:04X}",
                             arg,
                             zp_idx,
                             ptr,
                             target),
        }
    }
    fn indirect_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let base_ptr = self.cpu.mem.read_w(arg as u16);
        let ptr = base_ptr.wrapping_add(self.cpu.y as u16);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ ({:02X}),Y = {:04X} @ {:04X} = {:04X}",
                             arg,
                             base_ptr,
                             ptr,
                             target),
        }
    }

    // Instructions
    // Stores
    fn stx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STX")
    }
    fn sta(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STA")
    }

    // Loads
    fn ldx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDX")
    }
    fn lda(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDA")
    }

    // Logic/Math Ops
    fn bit(&mut self, instr: PartialInstruction) -> String {
        instr.finish("BIT")
    }
    fn and(&mut self, instr: PartialInstruction) -> String {
        instr.finish("AND")
    }
    fn ora(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ORA")
    }
    fn eor(&mut self, instr: PartialInstruction) -> String {
        instr.finish("EOR")
    }
    fn adc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ADC")
    }
    fn cmp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CMP")
    }

    // Jumps
    fn jmp(&mut self) -> String {
        format!("JMP ${:04X}", self.read_w_incr_pc())
    }
    fn jmpi(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JMP ({:04X}) = {:04X}", arg, self.cpu.mem.read_w(arg))
    }
    fn jsr(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JSR ${:04X}", arg)
    }
    fn rts(&mut self) -> String {
        "RTS".to_string()
    }

    // Branches
    fn bcs(&mut self) -> String {
        self.branch("BCS")
    }
    fn bcc(&mut self) -> String {
        self.branch("BCC")
    }
    fn beq(&mut self) -> String {
        self.branch("BEQ")
    }
    fn bne(&mut self) -> String {
        self.branch("BNE")
    }
    fn bvs(&mut self) -> String {
        self.branch("BVS")
    }
    fn bvc(&mut self) -> String {
        self.branch("BVC")
    }
    fn bmi(&mut self) -> String {
        self.branch("BMI")
    }
    fn bpl(&mut self) -> String {
        self.branch("BPL")
    }

    fn branch(&mut self, instr: &str) -> String {
        let arg = self.read_incr_pc();
        format!("{:3} ${:04X}", instr, self.relative_addr(arg))
    }

    // Stack
    fn plp(&mut self) -> String {
        "PLP".to_string()
    }
    fn php(&mut self) -> String {
        "PHP".to_string()
    }
    fn pla(&mut self) -> String {
        "PLA".to_string()
    }
    fn pha(&mut self) -> String {
        "PHA".to_string()
    }

    // Misc
    fn nop(&mut self) -> String {
        "NOP".to_string()
    }
    fn sec(&mut self) -> String {
        "SEC".to_string()
    }
    fn clc(&mut self) -> String {
        "CLC".to_string()
    }
    fn sei(&mut self) -> String {
        "SEI".to_string()
    }
    fn sed(&mut self) -> String {
        "SED".to_string()
    }
    fn cld(&mut self) -> String {
        "CLD".to_string()
    }
    fn clv(&mut self) -> String {
        "CLV".to_string()
    }

    pub fn decode(mut self) -> Instruction {
        let opcode = self.read_incr_pc();
        let str: String = decode_opcode!(opcode, self);
        Instruction {
            bytes: self.bytes,
            str: str,
        }
    }

    fn relative_addr(&self, disp: u8) -> u16 {
        let disp = disp as i16;
        let pc = self.pc as i16;
        pc.wrapping_add(disp) as u16
    }

    fn read_incr_pc(&mut self) -> u8 {
        let val: u8 = self.cpu.mem.read(self.pc);
        self.bytes.push(val);
        self.pc = self.pc.wrapping_add(1);
        val
    }

    fn read_w_incr_pc(&mut self) -> u16 {
        ((self.read_incr_pc() as u16) << 0) | ((self.read_incr_pc() as u16) << 8)
    }
}
<commit_msg>Implemented even more instructions.<commit_after>use memory::MemSegment;
use cpu::CPU;

pub struct Disassembler<'a> {
    pc: u16,
    cpu: &'a mut CPU,
    bytes: Vec<u8>,
}

struct PartialInstruction {
    pattern: String,
}

impl PartialInstruction {
    fn finish(self, instr: &str) -> String {
        self.pattern.replace("$$$", instr).clone()
    }
}

pub struct Instruction {
    pub bytes: Vec<u8>,
    pub str: String,
}

impl<'a> Disassembler<'a> {
    pub fn new(cpu: &'a mut CPU) -> Disassembler {
        Disassembler {
            pc: cpu.pc,
            cpu: cpu,
            bytes: vec![],
        }
    }

    // Addressing modes
    fn immediate(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ #${:02X}", self.read_incr_pc()) }
    }
    fn absolute(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ #${:04X} = {:02X}", arg, self.cpu.mem.read(arg)),
        }
    }
    fn absolute_x(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.x as u16);
        PartialInstruction {
            pattern: format!("$$$ #${:04X},X @ {:02X} = {:02X}",
                             arg,
                             self.cpu.x,
                             self.cpu.mem.read(target)),
        }
    }
    fn absolute_y(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.y as u16);
        PartialInstruction {
            pattern: format!("$$$ #${:04X},Y @ {:02X} = {:02X}",
                             arg,
                             self.cpu.y,
                             self.cpu.mem.read(target)),
        }
    }
    fn zero_page(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ ${:02X} = {:02X}", arg, self.cpu.mem.read(arg as u16)),
        }
    }
    fn zero_page_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.x);
        PartialInstruction {
            pattern: format!("$$$ #${:02X},X @ {:02X} = {:02X}",
                             arg,
                             self.cpu.x,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn zero_page_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.y);
        PartialInstruction {
            pattern: format!("$$$ #${:02X},Y @ {:02X} = {:02X}",
                             arg,
                             self.cpu.y,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn indirect_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let zp_idx = arg.wrapping_add(self.cpu.x);
        let ptr = self.cpu.mem.read_w(zp_idx as u16);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ ({:02X},X) @ {:02X} = {:04X} = {:04X}",
                             arg,
                             zp_idx,
                             ptr,
                             target),
        }
    }
    fn indirect_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let base_ptr = self.cpu.mem.read_w(arg as u16);
        let ptr = base_ptr.wrapping_add(self.cpu.y as u16);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ ({:02X}),Y = {:04X} @ {:04X} = {:04X}",
                             arg,
                             base_ptr,
                             ptr,
                             target),
        }
    }

    // Instructions
    // Stores
    fn stx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STX")
    }
    fn sta(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STA")
    }

    // Loads
    fn ldx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDX")
    }
    fn lda(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDA")
    }
    fn ldy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDY")
    }

    // Logic/Math Ops
    fn bit(&mut self, instr: PartialInstruction) -> String {
        instr.finish("BIT")
    }
    fn and(&mut self, instr: PartialInstruction) -> String {
        instr.finish("AND")
    }
    fn ora(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ORA")
    }
    fn eor(&mut self, instr: PartialInstruction) -> String {
        instr.finish("EOR")
    }
    fn adc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ADC")
    }
    fn sbc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SBC")
    }
    fn cmp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CMP")
    }
    fn cpx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPX")
    }
    fn cpy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPY")
    }
    fn inc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("INC")
    }
    fn iny(&mut self) -> String {
        "INY".to_string()
    }
    fn inx(&mut self) -> String {
        "INX".to_string()
    }
    fn dec(&mut self, instr: PartialInstruction) -> String {
        instr.finish("DEC")
    }
    fn dey(&mut self) -> String {
        "DEY".to_string()
    }
    fn dex(&mut self) -> String {
        "DEX".to_string()
    }

    // Jumps
    fn jmp(&mut self) -> String {
        format!("JMP ${:04X}", self.read_w_incr_pc())
    }
    fn jmpi(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JMP ({:04X}) = {:04X}", arg, self.cpu.mem.read_w(arg))
    }
    fn jsr(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JSR ${:04X}", arg)
    }
    fn rts(&mut self) -> String {
        "RTS".to_string()
    }

    // Branches
    fn bcs(&mut self) -> String {
        self.branch("BCS")
    }
    fn bcc(&mut self) -> String {
        self.branch("BCC")
    }
    fn beq(&mut self) -> String {
        self.branch("BEQ")
    }
    fn bne(&mut self) -> String {
        self.branch("BNE")
    }
    fn bvs(&mut self) -> String {
        self.branch("BVS")
    }
    fn bvc(&mut self) -> String {
        self.branch("BVC")
    }
    fn bmi(&mut self) -> String {
        self.branch("BMI")
    }
    fn bpl(&mut self) -> String {
        self.branch("BPL")
    }

    fn branch(&mut self, instr: &str) -> String {
        let arg = self.read_incr_pc();
        format!("{:3} ${:04X}", instr, self.relative_addr(arg))
    }

    // Stack
    fn plp(&mut self) -> String {
        "PLP".to_string()
    }
    fn php(&mut self) -> String {
        "PHP".to_string()
    }
    fn pla(&mut self) -> String {
        "PLA".to_string()
    }
    fn pha(&mut self) -> String {
        "PHA".to_string()
    }

    // Misc
    fn nop(&mut self) -> String {
        "NOP".to_string()
    }
    fn sec(&mut self) -> String {
        "SEC".to_string()
    }
    fn clc(&mut self) -> String {
        "CLC".to_string()
    }
    fn sei(&mut self) -> String {
        "SEI".to_string()
    }
    fn sed(&mut self) -> String {
        "SED".to_string()
    }
    fn cld(&mut self) -> String {
        "CLD".to_string()
    }
    fn clv(&mut self) -> String {
        "CLV".to_string()
    }
    fn tax(&mut self) -> String {
        "TAX".to_string()
    }
    fn tay(&mut self) -> String {
        "TAY".to_string()
    }

    pub fn decode(mut self) -> Instruction {
        let opcode = self.read_incr_pc();
        let str: String = decode_opcode!(opcode, self);
        Instruction {
            bytes: self.bytes,
            str: str,
        }
    }

    fn relative_addr(&self, disp: u8) -> u16 {
        let disp = disp as i16;
        let pc = self.pc as i16;
        pc.wrapping_add(disp) as u16
    }

    fn read_incr_pc(&mut self) -> u8 {
        let val: u8 = self.cpu.mem.read(self.pc);
        self.bytes.push(val);
        self.pc = self.pc.wrapping_add(1);
        val
    }

    fn read_w_incr_pc(&mut self) -> u16 {
        ((self.read_incr_pc() as u16) << 0) | ((self.read_incr_pc() as u16) << 8)
    }
}
<|endoftext|>


<commit_before>use error::*;

/// Reprensents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Argument {
            name: name.into(),
            atype: atype.map(S::into),
        }
    }
}

/// Reprensents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Option<Vec<Argument>>,
    pub description: Option<Vec<String>>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_none());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Function {
            name: name.into(),
            return_type: None,
            arguments: None,
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Result<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| "Function type can not be parsed from signature.")?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// #TL_TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #TL_EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #TL_EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// #!TL_TESTCASE
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        self.description = Some(
            description
                .split('\n')
                .map(|fd| {
                    String::from(
                        fd.trim_left()
                            .trim_left_matches('*')
                            .trim_left_matches('/')
                            .trim_left(),
                    )
                })
                .filter(|ref c| !c.is_empty() && c.as_str() != "**")
                .collect(),
        )
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        if arguments.is_empty() {
            self.arguments = None;
        } else {
            self.arguments = Some(arguments.into());
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
/// The different types an Entitiy can have.
pub enum EntityType {
    /// A class definition.
    Class(Entity),

    /// A namespace.
    Namespace(Entity),

    /// The index of a new entity hierarchy.
    Index(Entity),
}

/// The representation of an Entity as a possbile generic node on the
/// abstract syntax tree. An Entity has to be kind of a EntityType.
#[derive(Clone, Debug, PartialEq)]
pub struct Entity {
    pub name: String,
    pub entities: Option<Vec<EntityType>>,
    pub functions: Option<Vec<Function>>,
}

impl Entity {
    /// Creates a new Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Entity;
    ///
    /// let class = Entity::new("testClass");
    ///
    /// assert!(class.functions.is_none());
    /// assert!(class.entities.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Entity {
            name: name.into(),
            entities: None,
            functions: None,
        }
    }

    /// Adds an Entity to the Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Entity, EntityType};
    ///
    /// let mut entity = Entity::new("outer_entity");
    /// let entity_type = EntityType::Class(Entity::new("inner_entity"));
    /// entity.add_entity(entity_type);
    ///
    /// assert!(entity.entities.is_some());
    /// ```
    pub fn add_entity(&mut self, entity: EntityType) -> Option<&mut EntityType> {
        if self.entities.is_none() {
            self.entities = Some(Vec::new());
        }

        if let Some(entities) = &mut self.entities {
            entities.push(entity);
            return entities.last_mut();
        }

        None
    }

    /// Adds a Function to the Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Entity, Function};
    ///
    /// let mut entity = Entity::new("entity");
    /// let function = Function::new("func");
    /// entity.add_function(function);
    ///
    /// assert!(entity.functions.is_some());
    /// ```
    pub fn add_function(&mut self, function: Function) -> Option<&mut Function> {
        if self.functions.is_none() {
            self.functions = Some(Vec::new());
        }

        if let Some(functions) = &mut self.functions {
            functions.push(function);
            return functions.last_mut();
        }

        None
    }
}
<commit_msg>Add enum type to entity<commit_after>use error::*;

/// Reprensents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
    pub value: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Argument {
            name: name.into(),
            atype: atype.map(S::into),
            value: None,
        }
    }

    /// Sets a value to the argument.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Argument;
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// assert!(argument.value.is_some());
    ///
    /// ```
    pub fn set_value(&mut self, value: &str) {
        self.value = Some(String::from(value));
    }
}

/// Reprensents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Option<Vec<Argument>>,
    pub description: Option<Vec<String>>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_none());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Function {
            name: name.into(),
            return_type: None,
            arguments: None,
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Result<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| "Function type can not be parsed from signature.")?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// #TL_TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #TL_EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #TL_EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// #!TL_TESTCASE
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        self.description = Some(
            description
                .split('\n')
                .map(|fd| {
                    String::from(
                        fd.trim_left()
                            .trim_left_matches('*')
                            .trim_left_matches('/')
                            .trim_left(),
                    )
                })
                .filter(|ref c| !c.is_empty() && c.as_str() != "**")
                .collect(),
        )
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        if arguments.is_empty() {
            self.arguments = None;
        } else {
            self.arguments = Some(arguments.into());
        }
    }
}

/// Reprensents a parsed enum argument.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Enum {
    pub name: String,
    pub etype: Option<String>,
    pub arguments: Option<Vec<Argument>>,
}

impl Enum {
    /// Creates a new Enum instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Enum;
    ///
    /// let enumeration = Enum::new("testEnum");
    ///
    /// assert_eq!(enumeration.name, String::from("testEnum"));
    /// assert!(enumeration.etype.is_none());
    /// assert!(enumeration.arguments.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Enum {
            name: name.into(),
            etype: None,
            arguments: None,
        }
    }

    /// Sets arguments for the Enum.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Argument, Enum};
    ///
    /// let mut enumeration = Enum::new("testEnum");
    /// let args = vec![Argument::new("Zero", Some("0")), Argument::new("Two", Some("2"))];
    /// enumeration.set_arguments(&args);
    ///
    /// assert!(enumeration.arguments.is_some());
    /// assert_eq!(enumeration.arguments.unwrap().len(), 2);
    /// ```
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        if arguments.is_empty() {
            self.arguments = None;
        } else {
            self.arguments = Some(arguments.into());
        }
    }

    /// Adds an Argument to the Enum argument list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Argument, Enum};
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// let mut enumeration = Enum::new("enum");
    /// enumeration.push_argument(argument);
    ///
    /// assert!(enumeration.arguments.is_some());
    /// assert_eq!(enumeration.arguments.unwrap().len(), 1);
    ///
    /// ```
    pub fn push_argument(&mut self, argument: Argument) {
        if self.arguments.is_none() {
            self.arguments = Some(Vec::new());
        }

        if let Some(arguments) = &mut self.arguments {
            arguments.push(argument);
        }
    }
}

/// The different types an Entitiy can have.
#[derive(Clone, Debug, PartialEq)]
pub enum EntityType {
    /// A class definition.
    Class(Entity),

    /// A namespace.
    Namespace(Entity),

    /// The index of a new entity hierarchy.
    Index(Entity),
}

/// The representation of an Entity as a possbile generic node on the
/// abstract syntax tree. An Entity has to be kind of a EntityType.
#[derive(Clone, Debug, PartialEq)]
pub struct Entity {
    pub name: String,
    pub entities: Option<Vec<EntityType>>,
    pub functions: Option<Vec<Function>>,
}

impl Entity {
    /// Creates a new Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::Entity;
    ///
    /// let class = Entity::new("testClass");
    ///
    /// assert!(class.functions.is_none());
    /// assert!(class.entities.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Entity {
            name: name.into(),
            entities: None,
            functions: None,
        }
    }

    /// Adds an Entity to the Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Entity, EntityType};
    ///
    /// let mut entity = Entity::new("outer_entity");
    /// let entity_type = EntityType::Class(Entity::new("inner_entity"));
    /// entity.add_entity(entity_type);
    ///
    /// assert!(entity.entities.is_some());
    /// ```
    pub fn add_entity(&mut self, entity: EntityType) -> Option<&mut EntityType> {
        if self.entities.is_none() {
            self.entities = Some(Vec::new());
        }

        if let Some(entities) = &mut self.entities {
            entities.push(entity);
            return entities.last_mut();
        }

        None
    }

    /// Adds a Function to the Entity instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::entity::{Entity, Function};
    ///
    /// let mut entity = Entity::new("entity");
    /// let function = Function::new("func");
    /// entity.add_function(function);
    ///
    /// assert!(entity.functions.is_some());
    /// ```
    pub fn add_function(&mut self, function: Function) -> Option<&mut Function> {
        if self.functions.is_none() {
            self.functions = Some(Vec::new());
        }

        if let Some(functions) = &mut self.functions {
            functions.push(function);
            return functions.last_mut();
        }

        None
    }
}
<|endoftext|>


<commit_before>use std::{fmt, io, string};

pub enum OscError {
    StringError(string::FromUtf8Error),
    ReadError(io::Error),
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<commit_msg>Add byteorder Error<commit_after>use byteorder;
use std::{fmt, io, string};

pub enum OscError {
    StringError(string::FromUtf8Error),
    ReadError(io::Error),
    ByteOrderError(byteorder::Error),
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<|endoftext|>


<commit_before>//! Contains functions for performing XML special characters escaping.

use std::borrow::Cow;

use self::Value::{C, S};
use self::Process::{B, O};

enum Value {
    C(char),
    S(&'static str)
}

impl Value {
    fn dispatch_for_attribute(c: char) -> Value {
        match c {
            '<'  => S("<"),
            '>'  => S(">"),
            '"'  => S("""),
            '\'' => S("'"),
            '&'  => S("&"),
            _    => C(c)
        }
    }

    fn dispatch_for_pcdata(c: char) -> Value {
        match c {
            '<'  => S("<"),
            '&'  => S("&"),
            _    => C(c)
        }
    }
}

enum Process<'a> {
    B(&'a str),
    O(String)
}

impl<'a> Process<'a> {
    fn process(&mut self, (i, next): (usize, Value)) {
        match next {
            S(s) => if let O(ref mut o) = *self {
                o.push_str(s);
            } else if let B(b) = *self {
                let mut r = String::with_capacity(b.len() + s.len());
                r.push_str(&b[..i]);
                r.push_str(s);
                *self = O(r);
            },
            C(c) => match *self {
                B(_) => {}
                O(ref mut o) => o.push(c)
            }
        }
    }

    fn into_result(self) -> Cow<'a, str> {
        match self {
            B(b) => Cow::Borrowed(b),
            O(o) => Cow::Owned(o)
        }
    }
}

impl<'a> Extend<(usize, Value)> for Process<'a> {
    fn extend<I: IntoIterator<Item=(usize, Value)>>(&mut self, it: I) {
        for v in it.into_iter() {
            self.process(v);
        }
    }
}

fn escape_str(s: &str, dispatch: fn(char) -> Value) -> Cow<str> {
    let mut p = B(s);
    p.extend(s.char_indices().map(|(ind, c)| (ind, dispatch(c))));
    p.into_result()
}

/// Performs escaping of common XML characters inside an attribute value.
///
/// This function replaces several important markup characters with their
/// entity equivalents:
///
/// * `<` → `<`
/// * `>` → `>`
/// * `"` → `"`
/// * `'` → `'`
/// * `&` → `&`
///
/// The resulting string is safe to use inside XML attribute values or in PCDATA sections.
///
/// Does not perform allocations if the given string does not contain escapable characters.
#[inline]
pub fn escape_str_attribute(s: &str) -> Cow<str> {
    escape_str(s, Value::dispatch_for_attribute)
}

/// Performs escaping of common XML characters inside PCDATA.
///
/// This function replaces several important markup characters with their
/// entity equivalents:
///
/// * `<` → `<`
/// * `&` → `&`
///
/// The resulting string is safe to use inside PCDATA sections but NOT inside attribute values.
///
/// Does not perform allocations if the given string does not contain escapable characters.
#[inline]
pub fn escape_str_pcdata(s: &str) -> Cow<str> {
    escape_str(s, Value::dispatch_for_pcdata)
}

#[test]
fn test_escape() {
    assert_eq!(escape_str_pcdata("☃<"), "☃<");
}
<commit_msg>Improved the escape module code<commit_after>//! Contains functions for performing XML special characters escaping.

use std::borrow::Cow;

enum Value {
    Char(char),
    Str(&'static str)
}

impl Value {
    fn dispatch_for_attribute(c: char) -> Value {
        match c {
            '<'  => Value::Str("<"),
            '>'  => Value::Str(">"),
            '"'  => Value::Str("""),
            '\'' => Value::Str("'"),
            '&'  => Value::Str("&"),
            _    => Value::Char(c)
        }
    }

    fn dispatch_for_pcdata(c: char) -> Value {
        match c {
            '<'  => Value::Str("<"),
            '&'  => Value::Str("&"),
            _    => Value::Char(c)
        }
    }
}

enum Process<'a> {
    Borrowed(&'a str),
    Owned(String)
}

impl<'a> Process<'a> {
    fn process(&mut self, (i, next): (usize, Value)) {
        match next {
            Value::Str(s) => match *self {
                Process::Owned(ref mut o) => o.push_str(s),
                Process::Borrowed(b) => {
                    let mut r = String::with_capacity(b.len() + s.len());
                    r.push_str(&b[..i]);
                    r.push_str(s);
                    *self = Process::Owned(r);
                }
            },
            Value::Char(c) => match *self {
                Process::Borrowed(_) => {}
                Process::Owned(ref mut o) => o.push(c)
            }
        }
    }

    fn into_result(self) -> Cow<'a, str> {
        match self {
            Process::Borrowed(b) => Cow::Borrowed(b),
            Process::Owned(o) => Cow::Owned(o)
        }
    }
}

impl<'a> Extend<(usize, Value)> for Process<'a> {
    fn extend<I: IntoIterator<Item=(usize, Value)>>(&mut self, it: I) {
        for v in it.into_iter() {
            self.process(v);
        }
    }
}

fn escape_str(s: &str, dispatch: fn(char) -> Value) -> Cow<str> {
    let mut p = Process::Borrowed(s);
    p.extend(s.char_indices().map(|(ind, c)| (ind, dispatch(c))));
    p.into_result()
}

/// Performs escaping of common XML characters inside an attribute value.
///
/// This function replaces several important markup characters with their
/// entity equivalents:
///
/// * `<` → `<`
/// * `>` → `>`
/// * `"` → `"`
/// * `'` → `'`
/// * `&` → `&`
///
/// The resulting string is safe to use inside XML attribute values or in PCDATA sections.
///
/// Does not perform allocations if the given string does not contain escapable characters.
#[inline]
pub fn escape_str_attribute(s: &str) -> Cow<str> {
    escape_str(s, Value::dispatch_for_attribute)
}

/// Performs escaping of common XML characters inside PCDATA.
///
/// This function replaces several important markup characters with their
/// entity equivalents:
///
/// * `<` → `<`
/// * `&` → `&`
///
/// The resulting string is safe to use inside PCDATA sections but NOT inside attribute values.
///
/// Does not perform allocations if the given string does not contain escapable characters.
#[inline]
pub fn escape_str_pcdata(s: &str) -> Cow<str> {
    escape_str(s, Value::dispatch_for_pcdata)
}

#[cfg(test)]
mod tests {
    use super::{escape_str_pcdata, escape_str_attribute};

    // TODO: add more tests

    #[test]
    fn test_escape_multibyte_code_points() {
        assert_eq!(escape_str_attribute("☃<"), "☃<");
        assert_eq!(escape_str_pcdata("☃<"), "☃<");
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(proc_macro)]

extern crate gtk;
#[macro_use]
extern crate relm;
extern crate relm_attributes;
#[macro_use]
extern crate relm_derive;
#[macro_use]
extern crate relm_test;

use gtk::{
    ButtonExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::Vertical;
use relm::Widget;
use relm_attributes::widget;

use self::Msg::*;

// Define the structure of the model.
pub struct Model {
    counter: i32,
}

// The messages that can be sent to the update function.
#[derive(Msg)]
pub enum Msg {
    #[cfg(test)] Test,
    Decrement,
    Increment,
    Quit,
}

#[widget]
impl Widget for Win {
    // The initial model.
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    // Update the model according to the message received.
    fn update(&mut self, event: Msg) {
        match event {
            #[cfg(test)] Test => (),
            Decrement => self.model.counter -= 1,
            Increment => self.model.counter += 1,
            Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                // Set the orientation property of the Box.
                orientation: Vertical,
                // Create a Button inside the Box.
                #[name="inc_button"]
                gtk::Button {
                    // Send the message Increment when the button is clicked.
                    clicked => Increment,
                    // TODO: check if using two events of the same name work.
                    label: "+",
                },
                #[name="label"]
                gtk::Label {
                    // Bind the text property of the label to the counter attribute of the model.
                    text: &self.model.counter.to_string(),
                },
                #[name="dec_button"]
                gtk::Button {
                    clicked => Decrement,
                    label: "-",
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).unwrap();
}

#[cfg(test)]
mod tests {
    use gtk::LabelExt;

    use relm;
    use relm_test::click;

    use Win;

    #[test]
    fn label_change() {
        let (_component, widgets) = relm::init_test::<Win>(()).unwrap();
        let inc_button = &widgets.inc_button;
        let dec_button = &widgets.dec_button;
        let label = &widgets.label;

        assert_text!(label, 0);
        click(inc_button);
        assert_text!(label, 1);
        click(inc_button);
        assert_text!(label, 2);
        click(inc_button);
        assert_text!(label, 3);
        click(inc_button);
        assert_text!(label, 4);

        click(dec_button);
        assert_text!(label, 3);
        click(dec_button);
        assert_text!(label, 2);
        click(dec_button);
        assert_text!(label, 1);
        click(dec_button);
        assert_text!(label, 0);
        click(dec_button);
        assert_text!(label, -1);
    }
}
<commit_msg>Improve test of buttons-attribute<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(proc_macro)]

extern crate gtk;
#[macro_use]
extern crate relm;
extern crate relm_attributes;
#[macro_use]
extern crate relm_derive;
#[macro_use]
extern crate relm_test;

use gtk::{
    ButtonExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::Vertical;
use relm::Widget;
use relm_attributes::widget;

use self::Msg::*;

// Define the structure of the model.
pub struct Model {
    counter: i32,
}

// The messages that can be sent to the update function.
#[derive(Msg)]
pub enum Msg {
    #[cfg(test)] Test,
    Decrement,
    Increment,
    Quit,
}

#[widget]
impl Widget for Win {
    // The initial model.
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    // Update the model according to the message received.
    fn update(&mut self, event: Msg) {
        match event {
            #[cfg(test)] Test => (),
            Decrement => self.model.counter -= 1,
            Increment => self.model.counter += 1,
            Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                // Set the orientation property of the Box.
                orientation: Vertical,
                // Create a Button inside the Box.
                #[name="inc_button"]
                gtk::Button {
                    // Send the message Increment when the button is clicked.
                    clicked => Increment,
                    // TODO: check if using two events of the same name work.
                    label: "+",
                },
                #[name="label"]
                gtk::Label {
                    // Bind the text property of the label to the counter attribute of the model.
                    text: &self.model.counter.to_string(),
                },
                #[name="dec_button"]
                gtk::Button {
                    clicked => Decrement,
                    label: "-",
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).unwrap();
}

#[cfg(test)]
mod tests {
    use gtk::LabelExt;

    use relm;
    use relm_test::click;

    use Win;

    #[test]
    fn label_change() {
        let (_component, widgets) = relm::init_test::<Win>(()).unwrap();
        let inc_button = &widgets.inc_button;
        let dec_button = &widgets.dec_button;
        let label = &widgets.label;

        assert_label!(inc_button, "+");
        assert_label!(dec_button, "-");

        assert_text!(label, 0);
        click(inc_button);
        assert_text!(label, 1);
        click(inc_button);
        assert_text!(label, 2);
        click(inc_button);
        assert_text!(label, 3);
        click(inc_button);
        assert_text!(label, 4);

        click(dec_button);
        assert_text!(label, 3);
        click(dec_button);
        assert_text!(label, 2);
        click(dec_button);
        assert_text!(label, 1);
        click(dec_button);
        assert_text!(label, 0);
        click(dec_button);
        assert_text!(label, -1);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;

pub fn build() {
    use std::path::Path;

    let out_dir = ::std::env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("named.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named.rs");
    build_colors(&mut writer);
    let dest_path = Path::new(&out_dir).join("named_gradients.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named_gradients.rs");
    build_gradients(&mut writer);
}

#[cfg(feature = "named")]
pub fn build_colors(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_colors.txt").expect("could not open svg_colors.txt"));
    let mut entries = vec![];

    for line in reader.lines() {
        let line = line.unwrap();
        let mut parts = line.split('\t');
        let name = parts.next().expect("couldn't get the color name");
        let mut rgb = parts
            .next()
            .unwrap_or_else(|| panic!("couldn't get color for {}", name))
            .split(", ");
        let red: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get red for {}", name));
        let green: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get green for {}", name));
        let blue: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get blue for {}", name));

        writeln!(writer, "\n///

", name).unwrap();
        writeln!(writer, "pub const {}: crate::rgb::Srgb<u8> = crate::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap();

        entries.push((name.to_owned(), name.to_uppercase()));
    }

    gen_from_str(writer, &entries)
}

#[cfg(feature = "named_gradients")]
pub fn build_gradients(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader = BufReader::new(
        File::open("build/svg_gradients_mpl.txt").expect("could not open svg_gradients_mpl.txt"),
    );

    let mut line_iter = reader.lines();
    while let Some(Ok(line)) = line_iter.next() {
        //empty lines are allowed
        if line.is_empty() {
            continue;
        }
        let mut parts = line.split_whitespace();
        //every line should have the same info: name type number_of_colors [\n red green blue]^number_of_colors
        let name = parts.next().expect("couldn't get the color name");
        let color_type = parts.next().expect("couldn't get the type of the colors");
        //we assume that color_type is a rgb type
        let color_type = format!("crate::rgb::{}", color_type);
        let number_of_colors: usize = parts
            .next()
            .expect("couldn't get the number of colors")
            .parse()
            .unwrap_or_else(|_| panic!("couldn't parse the number of colors for color {}", name));
        writeln!(writer, "/// New matplotlib colormap by Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.").unwrap();
        writeln!(writer, "/// This gradient is perfectly perceptually-uniform, both in regular form and also when converted to black-and-white.").unwrap();
        writeln!(
            writer,
            "/// The colormap is released under the CC0 license public domain dedication."
        )
        .unwrap();
        write!(writer,
            "pub const {0}: crate::gradient::Gradient<{1}, [(f32,{1});{2}]> = crate::gradient::Gradient([",
            name.to_uppercase(), color_type, number_of_colors).unwrap();
        for i in 0..number_of_colors {
            let color = line_iter
                .next()
                .unwrap_or_else(|| panic!("less lines than stated colors in gradient {}", name))
                .unwrap_or_else(|_| panic!("couldn't read the {}th line of color {}", i, name));
            let mut rgb = color.split(',');
            let red: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th red-value for {}", i, name));
            let green: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th green-value for {}", i, name));
            let blue: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th blue-value for {}", i, name));
            write!(writer, "({:.10},{}{{red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData}}),", (i as f32/number_of_colors as f32), color_type, red, green, blue).unwrap();
        }
        writeln!(writer, "], ::core::marker::PhantomData);").unwrap();
    }
}

#[cfg(feature = "named_from_str")]
fn gen_from_str(writer: &mut File, entries: &[(String, String)]) {
    use std::io::Write;

    writer
        .write_all(
            "static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = phf::phf_map! {\n"
                .as_bytes(),
        )
        .unwrap();

    for (key, value) in entries {
        writeln!(writer, "    \"{}\" => {},", key, value).unwrap();
    }

    writer.write_all("};\n".as_bytes()).unwrap();
}

#[cfg(not(feature = "named"))]
pub fn build_colors(_writer: &mut File) {}

#[allow(unused)]
#[cfg(not(feature = "named_from_str"))]
fn gen_from_str(_writer: &mut File, _entries: &[(String, String)]) {}

#[allow(unused)]
#[cfg(not(feature = "named_gradients"))]
pub fn build_gradients(_writer: &mut File) {}
<commit_msg>Separate documentation of named gradients into two pargraphs.<commit_after>use std::fs::File;

pub fn build() {
    use std::path::Path;

    let out_dir = ::std::env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("named.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named.rs");
    build_colors(&mut writer);
    let dest_path = Path::new(&out_dir).join("named_gradients.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named_gradients.rs");
    build_gradients(&mut writer);
}

#[cfg(feature = "named")]
pub fn build_colors(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_colors.txt").expect("could not open svg_colors.txt"));
    let mut entries = vec![];

    for line in reader.lines() {
        let line = line.unwrap();
        let mut parts = line.split('\t');
        let name = parts.next().expect("couldn't get the color name");
        let mut rgb = parts
            .next()
            .unwrap_or_else(|| panic!("couldn't get color for {}", name))
            .split(", ");
        let red: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get red for {}", name));
        let green: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get green for {}", name));
        let blue: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get blue for {}", name));

        writeln!(writer, "\n///

", name).unwrap();
        writeln!(writer, "pub const {}: crate::rgb::Srgb<u8> = crate::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap();

        entries.push((name.to_owned(), name.to_uppercase()));
    }

    gen_from_str(writer, &entries)
}

#[cfg(feature = "named_gradients")]
pub fn build_gradients(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader = BufReader::new(
        File::open("build/svg_gradients_mpl.txt").expect("could not open svg_gradients_mpl.txt"),
    );

    let mut line_iter = reader.lines();
    while let Some(Ok(line)) = line_iter.next() {
        //empty lines are allowed
        if line.is_empty() {
            continue;
        }
        let mut parts = line.split_whitespace();
        //every line should have the same info: name type number_of_colors [\n red green blue]^number_of_colors
        let name = parts.next().expect("couldn't get the color name");
        let color_type = parts.next().expect("couldn't get the type of the colors");
        //we assume that color_type is a rgb type
        let color_type = format!("crate::rgb::{}", color_type);
        let number_of_colors: usize = parts
            .next()
            .expect("couldn't get the number of colors")
            .parse()
            .unwrap_or_else(|_| panic!("couldn't parse the number of colors for color {}", name));
        writeln!(writer, "/// New matplotlib colormap by Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.").unwrap();
        writeln!(writer, "///").unwrap();
        writeln!(writer, "/// This gradient is perfectly perceptually-uniform, both in regular form and also when converted to black-and-white.").unwrap();
        writeln!(
            writer,
            "/// The colormap is released under the CC0 license public domain dedication."
        )
        .unwrap();
        write!(writer,
            "pub const {0}: crate::gradient::Gradient<{1}, [(f32,{1});{2}]> = crate::gradient::Gradient([",
            name.to_uppercase(), color_type, number_of_colors).unwrap();
        for i in 0..number_of_colors {
            let color = line_iter
                .next()
                .unwrap_or_else(|| panic!("less lines than stated colors in gradient {}", name))
                .unwrap_or_else(|_| panic!("couldn't read the {}th line of color {}", i, name));
            let mut rgb = color.split(',');
            let red: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th red-value for {}", i, name));
            let green: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th green-value for {}", i, name));
            let blue: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th blue-value for {}", i, name));
            write!(writer, "({:.10},{}{{red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData}}),", (i as f32/number_of_colors as f32), color_type, red, green, blue).unwrap();
        }
        writeln!(writer, "], ::core::marker::PhantomData);").unwrap();
    }
}

#[cfg(feature = "named_from_str")]
fn gen_from_str(writer: &mut File, entries: &[(String, String)]) {
    use std::io::Write;

    writer
        .write_all(
            "static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = phf::phf_map! {\n"
                .as_bytes(),
        )
        .unwrap();

    for (key, value) in entries {
        writeln!(writer, "    \"{}\" => {},", key, value).unwrap();
    }

    writer.write_all("};\n".as_bytes()).unwrap();
}

#[cfg(not(feature = "named"))]
pub fn build_colors(_writer: &mut File) {}

#[allow(unused)]
#[cfg(not(feature = "named_from_str"))]
fn gen_from_str(_writer: &mut File, _entries: &[(String, String)]) {}

#[allow(unused)]
#[cfg(not(feature = "named_gradients"))]
pub fn build_gradients(_writer: &mut File) {}
<|endoftext|>


<commit_before>#[macro_use]
extern crate macros;

use std::collections::HashMap;

#[test]
fn test_empty() {
    let expected: HashMap<usize, usize> = HashMap::new();
    let computed: HashMap<usize, usize> = hashmap!();
    assert_eq!(computed, expected);
}

#[test]
#[ignore]
fn test_no_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    expected.insert(2, "two");
    assert_eq!(hashmap!(1 => "one", 2 => "two"), expected);
}

#[test]
#[ignore]
fn test_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert('h', 89);
    expected.insert('a', 1);
    expected.insert('s', 19);
    expected.insert('h', 8);
    assert_eq!(
        hashmap!(
            'h' => 89,
            'a' => 1,
            's' => 19,
            'h' => 8,
        ),
        expected
    );
}

#[test]
#[ignore]
fn test_nested() {
    let mut expected = HashMap::new();
    expected.insert("non-empty", {
        let mut subhashmap = HashMap::new();
        subhashmap.insert(23, 623);
        subhashmap.insert(34, 21);
        subhashmap
    });
    expected.insert("empty", HashMap::new());
    assert_eq!(
        hashmap!(
            "non-empty" => hashmap!(
                23 => 623,
                34 => 21
            ),
            "empty" => hashmap!()
        ),
        expected
    );
}
<commit_msg>macros: test macro without HashMap in scope<commit_after>#[macro_use]
extern crate macros;

use std::collections::HashMap;

#[test]
fn test_empty() {
    let expected: HashMap<usize, usize> = HashMap::new();
    let computed: HashMap<usize, usize> = hashmap!();
    assert_eq!(computed, expected);
}

#[test]
#[ignore]
fn test_no_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    expected.insert(2, "two");
    assert_eq!(hashmap!(1 => "one", 2 => "two"), expected);
}

#[test]
#[ignore]
fn test_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert('h', 89);
    expected.insert('a', 1);
    expected.insert('s', 19);
    expected.insert('h', 8);
    assert_eq!(
        hashmap!(
            'h' => 89,
            'a' => 1,
            's' => 19,
            'h' => 8,
        ),
        expected
    );
}

#[test]
#[ignore]
fn test_nested() {
    let mut expected = HashMap::new();
    expected.insert("non-empty", {
        let mut subhashmap = HashMap::new();
        subhashmap.insert(23, 623);
        subhashmap.insert(34, 21);
        subhashmap
    });
    expected.insert("empty", HashMap::new());
    assert_eq!(
        hashmap!(
            "non-empty" => hashmap!(
                23 => 623,
                34 => 21
            ),
            "empty" => hashmap!()
        ),
        expected
    );
}

mod test {
    #[test]
    #[ignore]
    fn type_not_in_scope() {
        let expected: ::std::collections::HashMap<(), ()> = hashmap!();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels,
            buffer: vec![]
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&self, card: Card) -> &Ante {
        println!("jump {}:{}", card.rank, card.suit);
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self//.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("hello.ante".as_slice()).run();
}
<commit_msg>Assignment expression<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static A: u32 = 65;
static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels,
            buffer: vec![]
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&self, card: Card) -> &Ante {
        println!("jump {}:{}", card.rank, card.suit);
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = std::char::from_u32(operands[0].suit).unwrap();

        if initial == A {
            initial = self.vars[target] as u32;
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = std::char::from_u32(operands[i].suit).unwrap();

            if rank == A {
                rank = self.vars[suit] as u32;
            }
            match suit {
                '♦' => initial += rank,
                '♥' => initial *= rank,
                '♠' => initial -= rank,
                '♣' => if rank != 0 {
                            initial /= rank;
                        } else {
                            self.exception("division by zero");
                        },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial as uint;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("hello.ante".as_slice()).run();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use wlroots::{project_box, Area, Capability, Compositor, CompositorBuilder, CursorBuilder,
              CursorHandler, CursorId, InputManagerHandler, Keyboard, KeyboardGrab,
              KeyboardHandle, KeyboardHandler, Origin, Output, OutputBuilder, OutputBuilderResult,
              OutputHandler, OutputLayout, OutputManagerHandler, Pointer, PointerHandler,
              Renderer, Seat, SeatHandler, SeatId, Size, Surface, XCursorTheme, XdgV6ShellHandler,
              XdgV6ShellManagerHandler, XdgV6ShellState, XdgV6ShellSurface,
              XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::wlroots_sys::wlr_key_state::WLR_KEY_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::{KEY_Escape, KEY_F1};

struct State {
    xcursor_theme: XCursorTheme,
    keyboard: Option<KeyboardHandle>,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>,
    seat_id: Option<SeatId>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                keyboard: None,
                seat_id: None,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {
    fn on_commit(&mut self,
                 compositor: &mut Compositor,
                 surface: &mut Surface,
                 shell: &mut XdgV6ShellSurface) {
    }
}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface)
                   -> Option<Box<XdgV6ShellHandler>> {
        shell.ping();
        match shell.state() {
            Some(&mut XdgV6ShellState::TopLevel(ref mut toplevel)) => {
                toplevel.set_activated(true);
            }
            _ => {}
        }
        let seat_id = {
            let state: &mut State = compositor.into();
            state.shells.push(shell.weak_reference());
            for (mut output, _) in state.layout.outputs() {
                output.run(|output| output.schedule_frame()).unwrap();
            }
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        let mut keyboard = seat.get_keyboard().expect("Seat did not have a keyboard set");
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else if key_event.key_state() == WLR_KEY_PRESSED {
                if key == KEY_F1 {
                    thread::spawn(move || {
                                      Command::new("weston-terminal").output().unwrap();
                                  });
                    return
                }
            }
        }
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        let seat_id = state.seat_id.unwrap();
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        seat.keyboard_notify_key(key_event.time_msec(),
                                 key_event.keycode(),
                                 key_event.key_state() as u32);
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      compositor: &mut Compositor,
                      keyboard: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        let seat_id = {
            let state: &mut State = compositor.into();
            state.keyboard = Some(keyboard.weak_reference());
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("Invalid seat id");
        seat.set_keyboard(keyboard.input_device());
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));

    {
        let seat_id = {
            let seat = Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
                .expect("Could not allocate the global seat");
            seat.set_capabilities(Capability::all());
            seat.id()
        };
        let state: &mut State = (&mut compositor).into();
        state.seat_id = Some(seat_id);
    }
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        let start = SystemTime::now();
                                        let now = start.duration_since(UNIX_EPOCH)
                                            .expect("Time went backwards");
                                        surface.send_frame_done(now);
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<commit_msg>fixed errors in test from renderer complication<commit_after>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use wlroots::{project_box, Area, Capability, Compositor, CompositorBuilder, CursorBuilder,
              CursorHandler, CursorId, InputManagerHandler, Keyboard, KeyboardGrab,
              KeyboardHandle, KeyboardHandler, Origin, Output, OutputBuilder, OutputBuilderResult,
              OutputHandler, OutputLayout, OutputManagerHandler, Pointer, PointerHandler,
              Renderer, Seat, SeatHandler, SeatId, Size, Surface, XCursorTheme, XdgV6ShellHandler,
              XdgV6ShellManagerHandler, XdgV6ShellState, XdgV6ShellSurface,
              XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::wlroots_sys::wlr_key_state::WLR_KEY_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::{KEY_Escape, KEY_F1};

struct State {
    xcursor_theme: XCursorTheme,
    keyboard: Option<KeyboardHandle>,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>,
    seat_id: Option<SeatId>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                keyboard: None,
                seat_id: None,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {
    fn on_commit(&mut self,
                 compositor: &mut Compositor,
                 surface: &mut Surface,
                 shell: &mut XdgV6ShellSurface) {
    }
}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface)
                   -> Option<Box<XdgV6ShellHandler>> {
        shell.ping();
        match shell.state() {
            Some(&mut XdgV6ShellState::TopLevel(ref mut toplevel)) => {
                toplevel.set_activated(true);
            }
            _ => {}
        }
        let seat_id = {
            let state: &mut State = compositor.into();
            state.shells.push(shell.weak_reference());
            for (mut output, _) in state.layout.outputs() {
                output.run(|output| output.schedule_frame()).unwrap();
            }
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        let mut keyboard = seat.get_keyboard().expect("Seat did not have a keyboard set");
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else if key_event.key_state() == WLR_KEY_PRESSED {
                if key == KEY_F1 {
                    thread::spawn(move || {
                                      Command::new("weston-terminal").output().unwrap();
                                  });
                    return
                }
            }
        }
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        let seat_id = state.seat_id.unwrap();
        let seat = compositor.seats.get(seat_id).expect("invalid seat id");
        seat.keyboard_notify_key(key_event.time_msec(),
                                 key_event.keycode(),
                                 key_event.key_state() as u32);
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output, None));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      compositor: &mut Compositor,
                      keyboard: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        let seat_id = {
            let state: &mut State = compositor.into();
            state.keyboard = Some(keyboard.weak_reference());
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("Invalid seat id");
        seat.set_keyboard(keyboard.input_device());
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));

    {
        let seat_id = {
            let seat = Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
                .expect("Could not allocate the global seat");
            seat.set_capabilities(Capability::all());
            seat.id()
        };
        let state: &mut State = (&mut compositor).into();
        state.seat_id = Some(seat_id);
    }
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        let start = SystemTime::now();
                                        let now = start.duration_since(UNIX_EPOCH)
                                                       .expect("Time went backwards");
                                        surface.send_frame_done(now);
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<|endoftext|>