<commit_before>use super::constant::*;
use super::module::*;
use super::signal::*;

use std::cell::RefCell;
use std::ptr;

/// A hardware register, created by the [`Module`]::[`reg`] method.
///
/// A `Register` is a stateful component that behaves like a [D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#D_flip-flop) (more precisely as a [positive-edge-triggered D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#Classical_positive-edge-triggered_D_flip-flop)).
///
/// It always has a current value represented by the [`value`] field (often referred to as `Q`) and a next value specified by the [`drive_next`] method (often referred to as `D`).
/// It will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect the next value.
///
/// Optionally, it also has a default value specified by the [`default_value`] method. If at any time its [`Module`]'s implicit reset is driven low, the register's [`value`] will reflect the default value.
/// Default values are used to provide a known register state on system power-on and reset, but are often omitted to reduce combinational logic (which ultimately is how default values are typically implemented), especially for registers on timing-critical data paths.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
///
/// let my_reg = m.reg("my_reg", 32);
/// my_reg.default_value(0xfadebabeu32); // Optional
/// my_reg.drive_next(!my_reg.value);
/// m.output("my_output", my_reg.value);
/// ```
///
/// [`default_value`]: #method.default_value
/// [`drive_next`]: #method.drive_next
/// [`Module`]: ./struct.Module.html
/// [`reg`]: ./struct.Module.html#method.reg
/// [`value`]: #structfield.value
#[must_use]
pub struct Register<'a> {
    pub(crate) data: &'a RegisterData<'a>,
    /// This `Register`'s current value.
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub value: &'a Signal<'a>,
}

impl<'a> Register<'a> {
    /// Specifies the default value for this `Register`.
    ///
    /// This `Register`'s `value` will reflect this default value when this `Register`'s [`Module`]'s implicit reset is asserted.
    ///
    /// By default, a `Register` does not have a default value, and it is not required to specify one. If a default value is not specified, then this `Register`'s `value` will not change when its [`Module`]'s implicit reset is asserted.
    ///
    /// # Panics
    ///
    /// Panics if this `Register` already has a default value specified, or if the specified `value` doesn't fit into this `Register`'s bit width.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg.value);
    /// m.output("my_output", my_reg.value);
    /// ```
    ///
    /// [`Module`]: ./struct.Module.html
    pub fn default_value<C: Into<Constant>>(&'a self, value: C) {
        if self.data.initial_value.borrow().is_some() {
            panic!("Attempted to specify a default value for register \"{}\" in module \"{}\", but this register already has a default value.", self.data.name, self.data.module.name);
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > self.data.bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into register \"{}\"'s bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, self.data.name, self.data.bit_width, numeric_value, required_bits);
        }
        *self.data.initial_value.borrow_mut() = Some(value);
    }

    /// Specifies the next value for this `Register`.
    ///
    /// A `Register` will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect this next value.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `n` belong to different [`Module`]s, if the bit widths of `self` and `n` aren't equal, or if this `Register`'s next value is already driven.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg.value); // my_reg's value will toggle with each positive clock edge
    /// m.output("my_output", my_reg.value);
    /// ```
    ///
    /// [`Module`]: ./struct.Module.html
    /// [`value`]: #structfield.value
    pub fn drive_next(&'a self, n: &'a Signal<'a>) {
        if !ptr::eq(self.data.module, n.module) {
            panic!("Attempted to drive register \"{}\"'s next value with a signal from another module.", self.data.name);
        }
        if n.bit_width() != self.data.bit_width {
            panic!("Attempted to drive register \"{}\"'s next value with a signal that has a different bit width than the register ({} and {}, respectively).", self.data.name, n.bit_width(), self.data.bit_width);
        }
        if self.data.next.borrow().is_some() {
            panic!("Attempted to drive register \"{}\"'s next value in module \"{}\", but this register's next value is already driven.", self.data.name, self.data.module.name);
        }
        *self.data.next.borrow_mut() = Some(n);
    }
}

pub(crate) struct RegisterData<'a> {
    pub module: &'a Module<'a>,

    pub name: String,
    pub initial_value: RefCell<Option<Constant>>,
    pub bit_width: u32,
    pub next: RefCell<Option<&'a Signal<'a>>>,
}

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

    #[test]
    #[should_panic(
        expected = "Attempted to specify a default value for register \"r\" in module \"a\", but this register already has a default value."
    )]
    fn default_value_already_specified_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 32);

        r.default_value(0xfadebabeu32);

        // Panic
        r.default_value(0xdeadbeefu32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 7);

        // Panic
        r.default_value(128u32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 2);

        // Panic
        r.default_value(128u64);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into register \"r\"'s bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 4);

        // Panic
        r.default_value(1023u128);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into register \"r\"'s bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 1);

        // Panic
        r.default_value(65536u32);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal from another module."
    )]
    fn drive_next_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a");
        let l = m1.lit(true, 1);

        let m2 = c.module("b");
        let r = m2.reg("r", 1);

        // Panic
        r.drive_next(l);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal that has a different bit width than the register (5 and 3, respectively)."
    )]
    fn drive_next_incompatible_bit_width_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 3);
        let i = m.input("i", 5);

        // Panic
        r.drive_next(i);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value in module \"a\", but this register's next value is already driven."
    )]
    fn drive_next_already_driven_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 32);
        let i = m.input("i", 32);

        r.drive_next(i);

        // Panic
        r.drive_next(i);
    }
}
<commit_msg>Fix links in Register::default_value docs<commit_after>use super::constant::*;
use super::module::*;
use super::signal::*;

use std::cell::RefCell;
use std::ptr;

/// A hardware register, created by the [`Module`]::[`reg`] method.
///
/// A `Register` is a stateful component that behaves like a [D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#D_flip-flop) (more precisely as a [positive-edge-triggered D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#Classical_positive-edge-triggered_D_flip-flop)).
///
/// It always has a current value represented by the [`value`] field (often referred to as `Q`) and a next value specified by the [`drive_next`] method (often referred to as `D`).
/// It will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect the next value.
///
/// Optionally, it also has a default value specified by the [`default_value`] method. If at any time its [`Module`]'s implicit reset is driven low, the register's [`value`] will reflect the default value.
/// Default values are used to provide a known register state on system power-on and reset, but are often omitted to reduce combinational logic (which ultimately is how default values are typically implemented), especially for registers on timing-critical data paths.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
///
/// let my_reg = m.reg("my_reg", 32);
/// my_reg.default_value(0xfadebabeu32); // Optional
/// my_reg.drive_next(!my_reg.value);
/// m.output("my_output", my_reg.value);
/// ```
///
/// [`default_value`]: #method.default_value
/// [`drive_next`]: #method.drive_next
/// [`Module`]: ./struct.Module.html
/// [`reg`]: ./struct.Module.html#method.reg
/// [`value`]: #structfield.value
#[must_use]
pub struct Register<'a> {
    pub(crate) data: &'a RegisterData<'a>,
    /// This `Register`'s current value.
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub value: &'a Signal<'a>,
}

impl<'a> Register<'a> {
    /// Specifies the default value for this `Register`.
    ///
    /// This `Register`'s [`value`] will reflect this default value when this `Register`'s [`Module`]'s implicit reset is asserted.
    ///
    /// By default, a `Register` does not have a default value, and it is not required to specify one. If a default value is not specified, then this `Register`'s [`value`] will not change when its [`Module`]'s implicit reset is asserted.
    ///
    /// # Panics
    ///
    /// Panics if this `Register` already has a default value specified, or if the specified [`value`] doesn't fit into this `Register`'s bit width.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg.value);
    /// m.output("my_output", my_reg.value);
    /// ```
    ///
    /// [`Module`]: ./struct.Module.html
    /// [`value`]: #structfield.value
    pub fn default_value<C: Into<Constant>>(&'a self, value: C) {
        if self.data.initial_value.borrow().is_some() {
            panic!("Attempted to specify a default value for register \"{}\" in module \"{}\", but this register already has a default value.", self.data.name, self.data.module.name);
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > self.data.bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into register \"{}\"'s bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, self.data.name, self.data.bit_width, numeric_value, required_bits);
        }
        *self.data.initial_value.borrow_mut() = Some(value);
    }

    /// Specifies the next value for this `Register`.
    ///
    /// A `Register` will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect this next value.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `n` belong to different [`Module`]s, if the bit widths of `self` and `n` aren't equal, or if this `Register`'s next value is already driven.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg.value); // my_reg's value will toggle with each positive clock edge
    /// m.output("my_output", my_reg.value);
    /// ```
    ///
    /// [`Module`]: ./struct.Module.html
    /// [`value`]: #structfield.value
    pub fn drive_next(&'a self, n: &'a Signal<'a>) {
        if !ptr::eq(self.data.module, n.module) {
            panic!("Attempted to drive register \"{}\"'s next value with a signal from another module.", self.data.name);
        }
        if n.bit_width() != self.data.bit_width {
            panic!("Attempted to drive register \"{}\"'s next value with a signal that has a different bit width than the register ({} and {}, respectively).", self.data.name, n.bit_width(), self.data.bit_width);
        }
        if self.data.next.borrow().is_some() {
            panic!("Attempted to drive register \"{}\"'s next value in module \"{}\", but this register's next value is already driven.", self.data.name, self.data.module.name);
        }
        *self.data.next.borrow_mut() = Some(n);
    }
}

pub(crate) struct RegisterData<'a> {
    pub module: &'a Module<'a>,

    pub name: String,
    pub initial_value: RefCell<Option<Constant>>,
    pub bit_width: u32,
    pub next: RefCell<Option<&'a Signal<'a>>>,
}

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

    #[test]
    #[should_panic(
        expected = "Attempted to specify a default value for register \"r\" in module \"a\", but this register already has a default value."
    )]
    fn default_value_already_specified_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 32);

        r.default_value(0xfadebabeu32);

        // Panic
        r.default_value(0xdeadbeefu32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 7);

        // Panic
        r.default_value(128u32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 2);

        // Panic
        r.default_value(128u64);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into register \"r\"'s bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 4);

        // Panic
        r.default_value(1023u128);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into register \"r\"'s bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 1);

        // Panic
        r.default_value(65536u32);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal from another module."
    )]
    fn drive_next_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a");
        let l = m1.lit(true, 1);

        let m2 = c.module("b");
        let r = m2.reg("r", 1);

        // Panic
        r.drive_next(l);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal that has a different bit width than the register (5 and 3, respectively)."
    )]
    fn drive_next_incompatible_bit_width_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 3);
        let i = m.input("i", 5);

        // Panic
        r.drive_next(i);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value in module \"a\", but this register's next value is already driven."
    )]
    fn drive_next_already_driven_error() {
        let c = Context::new();

        let m = c.module("a");
        let r = m.reg("r", 32);
        let i = m.input("i", 32);

        r.drive_next(i);

        // Panic
        r.drive_next(i);
    }
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = para.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else if self.key_state.alt {
            let new_pos = self.to_motion(Inst(para, cmd));
            self.goto(new_pos);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('o') => {
                        // TODO: Autoindent (keep the same indentation level)
                        let y = self.y();
                        let ind = self.get_indent(y);
                        let last = ind.len();
                        self.text.insert(y + 1, ind);
                        self.goto((last, y + 1));
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                        let ins = self.next_inst();
                        let motion = self.to_motion(ins);
                        self.remove_rb(motion);
                    },
                    Char('G') => {
                        let last = self.text.len() - 1;
                        self.goto((0, last));
                    },
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                        } else {
                            let inst = self.next_inst();
                            let new = self.to_motion(inst);
                            self.cursor_mut().x = new.0;
                            self.cursor_mut().y = new.1;
                        }

                    },
//                    ????
//                    Char('K') => {
//                        self.goto((0, 0));
//                    },
//                    Char('J') => {
//                        self.goto((0, self.text.len() - 1));
//                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<commit_msg>Add cursor branching<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = para.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else if self.key_state.alt && cmd == Key::Char(' ') {
            self.next_cursor();
        } else if self.key_state.alt {
            let new_pos = self.to_motion(Inst(para, cmd));
            self.goto(new_pos);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('o') => {
                        // TODO: Autoindent (keep the same indentation level)
                        let y = self.y();
                        let ind = self.get_indent(y);
                        let last = ind.len();
                        self.text.insert(y + 1, ind);
                        self.goto((last, y + 1));
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                        let ins = self.next_inst();
                        let motion = self.to_motion(ins);
                        self.remove_rb(motion);
                    },
                    Char('G') => {
                        let last = self.text.len() - 1;
                        self.goto((0, last));
                    },
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                        } else {
                            let inst = self.next_inst();
                            let new = self.to_motion(inst);
                            self.cursor_mut().x = new.0;
                            self.cursor_mut().y = new.1;
                        }

                    },
                    Char('b') => {
                        // Branch cursor
                        let cursor = self.cursor().clone();
                        self.cursors.push(cursor);
                    },
//                    ????
//                    Char('K') => {
//                        self.goto((0, 0));
//                    },
//                    Char('J') => {
//                        self.goto((0, self.text.len() - 1));
//                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<|endoftext|>


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

//! Calculate [specified][specified] and [computed values][computed] from a
//! tree of DOM nodes and a set of stylesheets.
//!
//! [computed]: https://drafts.csswg.org/css-cascade/#computed
//! [specified]: https://drafts.csswg.org/css-cascade/#specified
//!
//! In particular, this crate contains the definitions of supported properties,
//! the code to parse them into specified values and calculate the computed
//! values based on the specified values, as well as the code to serialize both
//! specified and computed values.
//!
//! The main entry point is [`recalc_style_at`][recalc_style_at].
//!
//! [recalc_style_at]: traversal/fn.recalc_style_at.html
//!
//! Major dependencies are the [cssparser][cssparser] and [selectors][selectors]
//! crates.
//!
//! [cssparser]: ../cssparser/index.html
//! [selectors]: ../selectors/index.html

#![deny(warnings)]
#![deny(missing_docs)]

// FIXME(bholley): We need to blanket-allow unsafe code in order to make the
// gecko atom!() macro work. When Rust 1.14 is released [1], we can uncomment
// the commented-out attributes in regen_atoms.py and go back to denying unsafe
// code by default.
//
// [1] https://github.com/rust-lang/rust/issues/15701#issuecomment-251900615
//#![deny(unsafe_code)]
#![allow(unused_unsafe)]

#![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance

extern crate app_units;
extern crate arrayvec;
extern crate atomic_refcell;
extern crate bit_vec;
#[macro_use]
extern crate bitflags;
#[allow(unused_extern_crates)] extern crate byteorder;
#[cfg(feature = "gecko")] #[macro_use] #[no_link] extern crate cfg_if;
#[macro_use] extern crate cssparser;
extern crate euclid;
extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
extern crate itoa;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")]
#[macro_use]
pub extern crate nsstring_vendor as nsstring;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate num_integer;
extern crate num_traits;
extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot;
extern crate pdqsort;
#[cfg(feature = "gecko")] extern crate precomputed_hash;
extern crate rayon;
extern crate selectors;
#[cfg(feature = "servo")] #[macro_use] extern crate serde;
pub extern crate servo_arc;
#[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
#[cfg(feature = "servo")] extern crate servo_config;
#[cfg(feature = "servo")] extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style_derive;
#[macro_use]
extern crate style_traits;
extern crate time;
extern crate unicode_bidi;
#[allow(unused_extern_crates)]
extern crate unicode_segmentation;

#[macro_use]
mod macros;

pub mod animation;
pub mod applicable_declarations;
#[allow(missing_docs)] // TODO.
#[cfg(feature = "servo")] pub mod attr;
pub mod bezier;
pub mod bloom;
pub mod cache;
pub mod cascade_info;
pub mod context;
pub mod counter_style;
pub mod custom_properties;
pub mod data;
pub mod dom;
pub mod element_state;
#[cfg(feature = "servo")] mod encoding_support;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
pub mod invalidation;
#[allow(missing_docs)] // TODO.
pub mod logical_geometry;
pub mod matching;
pub mod media_queries;
pub mod parallel;
pub mod parser;
pub mod rule_tree;
pub mod scoped_tls;
pub mod selector_map;
pub mod selector_parser;
pub mod shared_lock;
pub mod sharing;
pub mod style_resolver;
pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential;
pub mod str;
pub mod style_adjuster;
pub mod stylesheet_set;
pub mod stylesheets;
pub mod thread_state;
pub mod timer;
pub mod traversal;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;

use std::fmt;
use style_traits::ToCss;

#[cfg(feature = "gecko")] pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as LocalName;

#[cfg(feature = "servo")] pub use servo_atoms::Atom;
#[cfg(feature = "servo")] pub use html5ever::Prefix;
#[cfg(feature = "servo")] pub use html5ever::LocalName;
#[cfg(feature = "servo")] pub use html5ever::Namespace;

/// The CSS properties supported by the style system.
/// Generated from the properties.mako.rs template by build.rs
#[macro_use]
#[allow(unsafe_code)]
#[deny(missing_docs)]
pub mod properties {
    include!(concat!(env!("OUT_DIR"), "/properties.rs"));
}

#[cfg(feature = "gecko")]
#[allow(unsafe_code, missing_docs)]
pub mod gecko_properties {
    include!(concat!(env!("OUT_DIR"), "/gecko_properties.rs"));
}

macro_rules! reexport_computed_values {
    ( $( $name: ident )+ ) => {
        /// Types for [computed values][computed].
        ///
        /// [computed]: https://drafts.csswg.org/css-cascade/#computed
        pub mod computed_values {
            $(
                pub use properties::longhands::$name::computed_value as $name;
            )+
            // Don't use a side-specific name needlessly:
            pub use properties::longhands::border_top_style::computed_value as border_style;
        }
    }
}
longhand_properties_idents!(reexport_computed_values);

/// Serializes as CSS a comma-separated list of any `T` that supports being
/// serialized as CSS.
pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
                                            list: &[T])
                                            -> fmt::Result
    where W: fmt::Write,
          T: ToCss,
{
    if list.is_empty() {
        return Ok(());
    }

    list[0].to_css(dest)?;

    for item in list.iter().skip(1) {
        write!(dest, ", ")?;
        item.to_css(dest)?;
    }

    Ok(())
}

#[cfg(feature = "gecko")] use gecko_string_cache::WeakAtom;
#[cfg(feature = "servo")] use servo_atoms::Atom as WeakAtom;

/// Extension methods for selectors::attr::CaseSensitivity
pub trait CaseSensitivityExt {
    /// Return whether two atoms compare equal according to this case sensitivity.
    fn eq_atom(self, a: &WeakAtom, b: &WeakAtom) -> bool;
}

impl CaseSensitivityExt for selectors::attr::CaseSensitivity {
    fn eq_atom(self, a: &WeakAtom, b: &WeakAtom) -> bool {
        match self {
            selectors::attr::CaseSensitivity::CaseSensitive => a == b,
            selectors::attr::CaseSensitivity::AsciiCaseInsensitive => a.eq_ignore_ascii_case(b),
        }
    }
}
<commit_msg>Remove #![deny(...)] from the style crate<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Calculate [specified][specified] and [computed values][computed] from a
//! tree of DOM nodes and a set of stylesheets.
//!
//! [computed]: https://drafts.csswg.org/css-cascade/#computed
//! [specified]: https://drafts.csswg.org/css-cascade/#specified
//!
//! In particular, this crate contains the definitions of supported properties,
//! the code to parse them into specified values and calculate the computed
//! values based on the specified values, as well as the code to serialize both
//! specified and computed values.
//!
//! The main entry point is [`recalc_style_at`][recalc_style_at].
//!
//! [recalc_style_at]: traversal/fn.recalc_style_at.html
//!
//! Major dependencies are the [cssparser][cssparser] and [selectors][selectors]
//! crates.
//!
//! [cssparser]: ../cssparser/index.html
//! [selectors]: ../selectors/index.html

// FIXME(bholley): We need to blanket-allow unsafe code in order to make the
// gecko atom!() macro work. When Rust 1.14 is released [1], we can uncomment
// the commented-out attributes in regen_atoms.py and go back to denying unsafe
// code by default.
//
// [1] https://github.com/rust-lang/rust/issues/15701#issuecomment-251900615
//#![deny(unsafe_code)]
#![allow(unused_unsafe)]

#![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance

extern crate app_units;
extern crate arrayvec;
extern crate atomic_refcell;
extern crate bit_vec;
#[macro_use]
extern crate bitflags;
#[allow(unused_extern_crates)] extern crate byteorder;
#[cfg(feature = "gecko")] #[macro_use] #[no_link] extern crate cfg_if;
#[macro_use] extern crate cssparser;
extern crate euclid;
extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
extern crate itoa;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")]
#[macro_use]
pub extern crate nsstring_vendor as nsstring;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate num_integer;
extern crate num_traits;
extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot;
extern crate pdqsort;
#[cfg(feature = "gecko")] extern crate precomputed_hash;
extern crate rayon;
extern crate selectors;
#[cfg(feature = "servo")] #[macro_use] extern crate serde;
pub extern crate servo_arc;
#[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
#[cfg(feature = "servo")] extern crate servo_config;
#[cfg(feature = "servo")] extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style_derive;
#[macro_use]
extern crate style_traits;
extern crate time;
extern crate unicode_bidi;
#[allow(unused_extern_crates)]
extern crate unicode_segmentation;

#[macro_use]
mod macros;

pub mod animation;
pub mod applicable_declarations;
#[allow(missing_docs)] // TODO.
#[cfg(feature = "servo")] pub mod attr;
pub mod bezier;
pub mod bloom;
pub mod cache;
pub mod cascade_info;
pub mod context;
pub mod counter_style;
pub mod custom_properties;
pub mod data;
pub mod dom;
pub mod element_state;
#[cfg(feature = "servo")] mod encoding_support;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
pub mod invalidation;
#[allow(missing_docs)] // TODO.
pub mod logical_geometry;
pub mod matching;
pub mod media_queries;
pub mod parallel;
pub mod parser;
pub mod rule_tree;
pub mod scoped_tls;
pub mod selector_map;
pub mod selector_parser;
pub mod shared_lock;
pub mod sharing;
pub mod style_resolver;
pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential;
pub mod str;
pub mod style_adjuster;
pub mod stylesheet_set;
pub mod stylesheets;
pub mod thread_state;
pub mod timer;
pub mod traversal;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;

use std::fmt;
use style_traits::ToCss;

#[cfg(feature = "gecko")] pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as LocalName;

#[cfg(feature = "servo")] pub use servo_atoms::Atom;
#[cfg(feature = "servo")] pub use html5ever::Prefix;
#[cfg(feature = "servo")] pub use html5ever::LocalName;
#[cfg(feature = "servo")] pub use html5ever::Namespace;

/// The CSS properties supported by the style system.
/// Generated from the properties.mako.rs template by build.rs
#[macro_use]
#[allow(unsafe_code)]
#[deny(missing_docs)]
pub mod properties {
    include!(concat!(env!("OUT_DIR"), "/properties.rs"));
}

#[cfg(feature = "gecko")]
#[allow(unsafe_code, missing_docs)]
pub mod gecko_properties {
    include!(concat!(env!("OUT_DIR"), "/gecko_properties.rs"));
}

macro_rules! reexport_computed_values {
    ( $( $name: ident )+ ) => {
        /// Types for [computed values][computed].
        ///
        /// [computed]: https://drafts.csswg.org/css-cascade/#computed
        pub mod computed_values {
            $(
                pub use properties::longhands::$name::computed_value as $name;
            )+
            // Don't use a side-specific name needlessly:
            pub use properties::longhands::border_top_style::computed_value as border_style;
        }
    }
}
longhand_properties_idents!(reexport_computed_values);

/// Serializes as CSS a comma-separated list of any `T` that supports being
/// serialized as CSS.
pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
                                            list: &[T])
                                            -> fmt::Result
    where W: fmt::Write,
          T: ToCss,
{
    if list.is_empty() {
        return Ok(());
    }

    list[0].to_css(dest)?;

    for item in list.iter().skip(1) {
        write!(dest, ", ")?;
        item.to_css(dest)?;
    }

    Ok(())
}

#[cfg(feature = "gecko")] use gecko_string_cache::WeakAtom;
#[cfg(feature = "servo")] use servo_atoms::Atom as WeakAtom;

/// Extension methods for selectors::attr::CaseSensitivity
pub trait CaseSensitivityExt {
    /// Return whether two atoms compare equal according to this case sensitivity.
    fn eq_atom(self, a: &WeakAtom, b: &WeakAtom) -> bool;
}

impl CaseSensitivityExt for selectors::attr::CaseSensitivity {
    fn eq_atom(self, a: &WeakAtom, b: &WeakAtom) -> bool {
        match self {
            selectors::attr::CaseSensitivity::CaseSensitive => a == b,
            selectors::attr::CaseSensitivity::AsciiCaseInsensitive => a.eq_ignore_ascii_case(b),
        }
    }
}
<|endoftext|>


<commit_before>use std::os::getenv;
use std::io::Command;
use std::io::File;

fn main() {
	let src_dir = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
	let dst_dir = Path::new(getenv("OUT_DIR").unwrap());

	let compiler = getenv("CC").unwrap_or("gcc".to_string());
	let executable = dst_dir.join("rust-constants");

	let c_src = src_dir.join("src/constants.c");
	let rust_dst = dst_dir.join("constants.rs");

	// Compile C code
	let mut cmd = Command::new(compiler);
	cmd.arg("-o").arg(&executable);
	cmd.arg(c_src);
	run(&mut cmd);

	// Run compiled binary and capture output
	let output = get_output(&mut Command::new(executable));
	let mut f = File::create(&rust_dst).unwrap();
	f.write_str(output.as_slice()).unwrap();
}

fn run(cmd: &mut Command) {
	let status = match cmd.status() {
		Ok(status) => status,
		Err(e) => panic!("failed to spawn process: {}", e),
	};

	if !status.success() {
		panic!("nonzero exit status: {}", status);
	}
}

fn get_output(cmd: &mut Command) -> String {
	let output = match cmd.output() {
		Ok(output) => output,
		Err(e) => panic!("failed to spawn process: {}", e),
	};

	if !output.status.success() {
		panic!("nonzero exit status: {}", output.status);
	}

	String::from_utf8(output.output).unwrap()
}
<commit_msg>Allow unstable features in build.rs<commit_after>#![allow(unstable)]

use std::os::getenv;
use std::io::Command;
use std::io::File;

fn main() {
	let src_dir = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
	let dst_dir = Path::new(getenv("OUT_DIR").unwrap());

	let compiler = getenv("CC").unwrap_or("gcc".to_string());
	let executable = dst_dir.join("rust-constants");

	let c_src = src_dir.join("src/constants.c");
	let rust_dst = dst_dir.join("constants.rs");

	// Compile C code
	let mut cmd = Command::new(compiler);
	cmd.arg("-o").arg(&executable);
	cmd.arg(c_src);
	run(&mut cmd);

	// Run compiled binary and capture output
	let output = get_output(&mut Command::new(executable));
	let mut f = File::create(&rust_dst).unwrap();
	f.write_str(output.as_slice()).unwrap();
}

fn run(cmd: &mut Command) {
	let status = match cmd.status() {
		Ok(status) => status,
		Err(e) => panic!("failed to spawn process: {}", e),
	};

	if !status.success() {
		panic!("nonzero exit status: {}", status);
	}
}

fn get_output(cmd: &mut Command) -> String {
	let output = match cmd.output() {
		Ok(output) => output,
		Err(e) => panic!("failed to spawn process: {}", e),
	};

	if !output.status.success() {
		panic!("nonzero exit status: {}", output.status);
	}

	String::from_utf8(output.output).unwrap()
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use std::fs;
use std::path::Path;

fn main() {
    configure_snappy();
}

fn configure_snappy() {
    if pkg_config::find_library("snappy").is_ok() {
        return;
    }
    // link the static library to simplify distribution
    println!("cargo:rustc-link-lib=static=snappy");
    println!("cargo:rustc-flags=-l c++");
    // For now just look in /usr/local/lib since this is the path where brew install snappy.
    if is_file_in("libsnappy.a", Path::new("/usr/local/lib")) {
        println!("cargo:rustc-link-search={}", "/usr/local/lib/");
    }
}

fn is_file_in(file: &str, folder: &Path) -> bool {
    let full = folder.join(file);
    match fs::metadata(full) {
        Ok(ref found) if found.is_file() => true,
        _ => false
    }

}
<commit_msg>Explicitly look in known folders<commit_after>extern crate pkg_config;

use std::fs;
use std::path::Path;

fn main() {
    configure_snappy();
}

fn configure_snappy() {
    // try pkg_config first
    if pkg_config::find_library("snappy").is_ok() {
        return;
    }
    // link the static library to simplify distribution
    println!("cargo:rustc-link-lib=static=snappy");
    println!("cargo:rustc-flags=-l c++");

    for f in vec!["/usr/lib","/usr/local/lib"] {
        if is_file_in("libsnappy.a", Path::new(f)) {
            println!("cargo:rustc-link-search={}", f);
        }
    }
}

fn is_file_in(file: &str, folder: &Path) -> bool {
    let full = folder.join(file);
    match fs::metadata(full) {
        Ok(ref found) if found.is_file() => true,
        _ => false
    }

}
<|endoftext|>


<commit_before>use std::io::{Command, File, Truncate, Write};

fn main()
{
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg("target/codegen")
                       .status()
                       .unwrap();
    let code = Command::new("./target/codegen").output().unwrap();
    if !code.status.success() {
        panic!("{}", String::from_utf8_lossy(code.error.as_slice()));
    }
    let mut f = File::open_mode(&Path::new("src/type_size.rs"), Truncate, Write);
    f.write(code.output.as_slice()).unwrap();
}
<commit_msg>Fix build script for packaging<commit_after>use std::io::{Command, File, Truncate, Write};
use std::os;

fn main()
{
    let dir = Path::new(os::getenv("OUT_DIR").unwrap());
    let out_file = dir.join("codegen");
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file.as_vec())
                       .status()
                       .unwrap();
    let code = Command::new(out_file.as_vec()).output().unwrap();
    if !code.status.success() {
        panic!("{}", String::from_utf8_lossy(code.error.as_slice()));
    }
    let mut f = File::open_mode(&Path::new("src/type_size.rs"), Truncate, Write);
    f.write(code.output.as_slice()).unwrap();
}
<|endoftext|>


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

use std::libc::c_float;
use std::ascii::StrAsciiExt;

use ast::*;
use self::color_data::{COLOR_KEYWORDS, COLOR_VALUES};

mod color_data;

// Try to match rust-azure’s AzFloat
pub type ColorFloat = c_float;

#[deriving(Clone)]
#[deriving(Eq)]
pub struct RGBA {
    // All in 0..1
    red: ColorFloat,
    green: ColorFloat,
    blue: ColorFloat,
    alpha: ColorFloat,
}

#[deriving(Clone)]
#[deriving(Eq)]
pub enum Color {
    CurrentColor,
    RGBA(RGBA),
}

// Return None on invalid/unsupported value (not a color)
impl Color {
    pub fn parse(component_value: &ComponentValue) -> Option<Color> {
        match *component_value {
            Hash(ref value) | IDHash(ref value) => parse_color_hash(*value),
            Ident(ref value) => parse_color_keyword(*value),
            Function(ref name, ref arguments) => parse_color_function(*name, *arguments),
            _ => None
        }
    }
}

#[inline]
fn parse_color_keyword(value: &str) -> Option<Color> {
    let lower_value = value.to_ascii_lower();
    match COLOR_KEYWORDS.bsearch_elem(&lower_value.as_slice()) {
        Some(index) => Some(RGBA(COLOR_VALUES[index])),
        None => if "currentcolor" == lower_value { Some(CurrentColor) }
                else { None }
    }
}

#[inline]
fn parse_color_hash(value: &str) -> Option<Color> {
    macro_rules! from_hex(
        ($c: expr) => {{
            let c = $c;
            match c as char {
                '0' .. '9' => c - ('0' as u8),
                'a' .. 'f' => c - ('a' as u8) + 10,
                'A' .. 'F' => c - ('A' as u8) + 10,
                _ => return None  // Not a valid color
            }
        }};
    )
    macro_rules! to_rgba(
        ($r: expr, $g: expr, $b: expr,) => {
            Some(RGBA(RGBA { red: $r as ColorFloat / 255.,
                             green: $g as ColorFloat / 255.,
                             blue: $b as ColorFloat / 255.,
                             alpha: 1. }))
        };
    )

    match value.len() {
        6 => to_rgba!(
            from_hex!(value[0]) * 16 + from_hex!(value[1]),
            from_hex!(value[2]) * 16 + from_hex!(value[3]),
            from_hex!(value[4]) * 16 + from_hex!(value[5]),
        ),
        3 => to_rgba!(
            from_hex!(value[0]) * 17,
            from_hex!(value[1]) * 17,
            from_hex!(value[2]) * 17,
        ),
        _ => None
    }
}

#[inline]
fn parse_color_function(name: &str, arguments: &[ComponentValue])
                        -> Option<Color> {
    let lower_name = name.to_ascii_lower();

    let (is_rgb, has_alpha) =
        if "rgba" == lower_name { (true, true) }
        else if "rgb" == lower_name { (true, false) }
        else if "hsl" == lower_name { (false, false) }
        else if "hsla" == lower_name { (false, true) }
        else { return None };

    let mut iter = arguments.skip_whitespace();
    macro_rules! expect_comma(
        () => ( if iter.next() != Some(&Comma) { return None } );
    )
    macro_rules! expect_percentage(
        () => ( match iter.next() {
            Some(&Percentage(ref v)) => v.value,
            _ => return None,
        });
    )
    macro_rules! expect_integer(
        () => ( match iter.next() {
            Some(&Number(ref v)) if v.int_value.is_some() => v.value,
            _ => return None,
        });
    )
    macro_rules! expect_number(
        () => ( match iter.next() {
            Some(&Number(ref v)) => v.value,
            _ => return None,
        });
    )

    let red: ColorFloat;
    let green: ColorFloat;
    let blue: ColorFloat;
    if is_rgb {
        // Either integers or percentages, but all the same type.
        match iter.next() {
            Some(&Number(ref v)) if v.int_value.is_some() => {
                red = (v.value as ColorFloat / 255.) as ColorFloat;
                expect_comma!();
                green = (expect_integer!() / 255.) as ColorFloat;
                expect_comma!();
                blue = (expect_integer!() / 255.) as ColorFloat;
            }
            Some(&Percentage(ref v)) => {
                red = (v.value as ColorFloat / 100.) as ColorFloat;
                expect_comma!();
                green = (expect_percentage!() / 100.) as ColorFloat;
                expect_comma!();
                blue = (expect_percentage!() / 100.) as ColorFloat;
            }
            _ => return None
        };
    } else {
        let hue = expect_number!() / 360.;
        let hue = hue - hue.floor();
        expect_comma!();
        let saturation = (expect_percentage!() / 100.).max(&0.).min(&1.);
        expect_comma!();
        let lightness = (expect_percentage!() / 100.).max(&0.).min(&1.);

        // http://www.w3.org/TR/css3-color/#hsl-color
        fn hue_to_rgb(m1: f64, m2: f64, mut h: f64) -> f64 {
            if h < 0. { h += 1. }
            if h > 1. { h -= 1. }

            if h * 6. < 1. { m1 + (m2 - m1) * h * 6. }
            else if h * 2. < 1. { m2 }
            else if h * 3. < 2. { m1 + (m2 - m1) * (2. / 3. - h) * 6. }
            else { m1 }
        }
        let m2 = if lightness <= 0.5 { lightness * (saturation + 1.) }
                 else { lightness + saturation - lightness * saturation };
        let m1 = lightness * 2. - m2;
        red = hue_to_rgb(m1, m2, hue + 1. / 3.) as ColorFloat;
        green = hue_to_rgb(m1, m2, hue) as ColorFloat;
        blue = hue_to_rgb(m1, m2, hue - 1. / 3.) as ColorFloat;
    }

    let alpha = if has_alpha {
        expect_comma!();
        (expect_number!()).max(&0.).min(&1.) as ColorFloat
    } else {
        1.
    };
    if iter.next().is_none() {
        Some(RGBA(RGBA { red: red, green: green, blue: blue, alpha: alpha }))
    } else {
        None
    }
}
<commit_msg>Use #[deriving(Clone, Eq)] rather than two attributes.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::libc::c_float;
use std::ascii::StrAsciiExt;

use ast::*;
use self::color_data::{COLOR_KEYWORDS, COLOR_VALUES};

mod color_data;

// Try to match rust-azure’s AzFloat
pub type ColorFloat = c_float;

#[deriving(Clone, Eq)]
pub struct RGBA {
    // All in 0..1
    red: ColorFloat,
    green: ColorFloat,
    blue: ColorFloat,
    alpha: ColorFloat,
}

#[deriving(Clone, Eq)]
pub enum Color {
    CurrentColor,
    RGBA(RGBA),
}

// Return None on invalid/unsupported value (not a color)
impl Color {
    pub fn parse(component_value: &ComponentValue) -> Option<Color> {
        match *component_value {
            Hash(ref value) | IDHash(ref value) => parse_color_hash(*value),
            Ident(ref value) => parse_color_keyword(*value),
            Function(ref name, ref arguments) => parse_color_function(*name, *arguments),
            _ => None
        }
    }
}

#[inline]
fn parse_color_keyword(value: &str) -> Option<Color> {
    let lower_value = value.to_ascii_lower();
    match COLOR_KEYWORDS.bsearch_elem(&lower_value.as_slice()) {
        Some(index) => Some(RGBA(COLOR_VALUES[index])),
        None => if "currentcolor" == lower_value { Some(CurrentColor) }
                else { None }
    }
}

#[inline]
fn parse_color_hash(value: &str) -> Option<Color> {
    macro_rules! from_hex(
        ($c: expr) => {{
            let c = $c;
            match c as char {
                '0' .. '9' => c - ('0' as u8),
                'a' .. 'f' => c - ('a' as u8) + 10,
                'A' .. 'F' => c - ('A' as u8) + 10,
                _ => return None  // Not a valid color
            }
        }};
    )
    macro_rules! to_rgba(
        ($r: expr, $g: expr, $b: expr,) => {
            Some(RGBA(RGBA { red: $r as ColorFloat / 255.,
                             green: $g as ColorFloat / 255.,
                             blue: $b as ColorFloat / 255.,
                             alpha: 1. }))
        };
    )

    match value.len() {
        6 => to_rgba!(
            from_hex!(value[0]) * 16 + from_hex!(value[1]),
            from_hex!(value[2]) * 16 + from_hex!(value[3]),
            from_hex!(value[4]) * 16 + from_hex!(value[5]),
        ),
        3 => to_rgba!(
            from_hex!(value[0]) * 17,
            from_hex!(value[1]) * 17,
            from_hex!(value[2]) * 17,
        ),
        _ => None
    }
}

#[inline]
fn parse_color_function(name: &str, arguments: &[ComponentValue])
                        -> Option<Color> {
    let lower_name = name.to_ascii_lower();

    let (is_rgb, has_alpha) =
        if "rgba" == lower_name { (true, true) }
        else if "rgb" == lower_name { (true, false) }
        else if "hsl" == lower_name { (false, false) }
        else if "hsla" == lower_name { (false, true) }
        else { return None };

    let mut iter = arguments.skip_whitespace();
    macro_rules! expect_comma(
        () => ( if iter.next() != Some(&Comma) { return None } );
    )
    macro_rules! expect_percentage(
        () => ( match iter.next() {
            Some(&Percentage(ref v)) => v.value,
            _ => return None,
        });
    )
    macro_rules! expect_integer(
        () => ( match iter.next() {
            Some(&Number(ref v)) if v.int_value.is_some() => v.value,
            _ => return None,
        });
    )
    macro_rules! expect_number(
        () => ( match iter.next() {
            Some(&Number(ref v)) => v.value,
            _ => return None,
        });
    )

    let red: ColorFloat;
    let green: ColorFloat;
    let blue: ColorFloat;
    if is_rgb {
        // Either integers or percentages, but all the same type.
        match iter.next() {
            Some(&Number(ref v)) if v.int_value.is_some() => {
                red = (v.value as ColorFloat / 255.) as ColorFloat;
                expect_comma!();
                green = (expect_integer!() / 255.) as ColorFloat;
                expect_comma!();
                blue = (expect_integer!() / 255.) as ColorFloat;
            }
            Some(&Percentage(ref v)) => {
                red = (v.value as ColorFloat / 100.) as ColorFloat;
                expect_comma!();
                green = (expect_percentage!() / 100.) as ColorFloat;
                expect_comma!();
                blue = (expect_percentage!() / 100.) as ColorFloat;
            }
            _ => return None
        };
    } else {
        let hue = expect_number!() / 360.;
        let hue = hue - hue.floor();
        expect_comma!();
        let saturation = (expect_percentage!() / 100.).max(&0.).min(&1.);
        expect_comma!();
        let lightness = (expect_percentage!() / 100.).max(&0.).min(&1.);

        // http://www.w3.org/TR/css3-color/#hsl-color
        fn hue_to_rgb(m1: f64, m2: f64, mut h: f64) -> f64 {
            if h < 0. { h += 1. }
            if h > 1. { h -= 1. }

            if h * 6. < 1. { m1 + (m2 - m1) * h * 6. }
            else if h * 2. < 1. { m2 }
            else if h * 3. < 2. { m1 + (m2 - m1) * (2. / 3. - h) * 6. }
            else { m1 }
        }
        let m2 = if lightness <= 0.5 { lightness * (saturation + 1.) }
                 else { lightness + saturation - lightness * saturation };
        let m1 = lightness * 2. - m2;
        red = hue_to_rgb(m1, m2, hue + 1. / 3.) as ColorFloat;
        green = hue_to_rgb(m1, m2, hue) as ColorFloat;
        blue = hue_to_rgb(m1, m2, hue - 1. / 3.) as ColorFloat;
    }

    let alpha = if has_alpha {
        expect_comma!();
        (expect_number!()).max(&0.).min(&1.) as ColorFloat
    } else {
        1.
    };
    if iter.next().is_none() {
        Some(RGBA(RGBA { red: red, green: green, blue: blue, alpha: alpha }))
    } else {
        None
    }
}
<|endoftext|>


<commit_before>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::{Fragment, Href};
use crate::aspect_ratio::AspectRatio;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;
use crate::viewbox::ViewBox;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct FeImage {
    base: Primitive,
    aspect: AspectRatio,
    href: Option<Href>,
}

impl Default for FeImage {
    /// Constructs a new `FeImage` with empty properties.
    #[inline]
    fn default() -> FeImage {
        FeImage {
            base: Primitive::new::<Self>(),
            aspect: AspectRatio::default(),
            href: None,
        }
    }
}

impl FeImage {
    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        draw_ctx: &mut DrawingCtx,
        bounds: Rect,
        fragment: &Fragment,
    ) -> Result<FilterResult, FilterError> {
        let acquired_drawable = acquired_nodes
            .acquire(fragment)
            .map_err(|_| FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();
        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        let image = draw_ctx.draw_node_to_surface(
            &drawable,
            acquired_nodes,
            &cascaded,
            ctx.paffine(),
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let surface = ctx.source_graphic().paint_image(bounds, &image, None)?;

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface,
                bounds: bounds.into(),
            },
        })
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        _draw_ctx: &DrawingCtx,
        bounds: Rect,
        unclipped_bounds: &Rect,
        url: &str,
    ) -> Result<FilterResult, FilterError> {
        // FIXME: translate the error better here
        let image = acquired_nodes
            .lookup_image(url)
            .map_err(|_| FilterError::InvalidInput)?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let rect = self.aspect.compute(
            &ViewBox(Rect::from_size(
                f64::from(image.width()),
                f64::from(image.height()),
            )),
            &unclipped_bounds,
        );

        let surface = ctx
            .source_graphic()
            .paint_image(bounds, &image, Some(rect))?;

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface,
                bounds: bounds.into(),
            },
        })
    }
}

impl SetAttributes for FeImage {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        self.base.set_attributes(pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "preserveAspectRatio") => self.aspect = attr.parse(value)?,

                // "path" is used by some older Adobe Illustrator versions
                expanded_name!(xlink "href") | expanded_name!("", "path") => {
                    let href = Href::parse(value)
                        .map_err(ValueErrorKind::from)
                        .attribute(attr)?;

                    self.href = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeImage {
    fn render(
        &self,
        node: &Node,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let bounds_builder = self.base.get_bounds(ctx, node.parent().as_ref())?;
        let bounds = bounds_builder.into_rect(draw_ctx);

        match self.href.as_ref() {
            Some(Href::PlainUrl(url)) => {
                let unclipped_bounds = bounds_builder.into_rect_without_clipping(draw_ctx);
                self.render_external_image(
                    ctx,
                    acquired_nodes,
                    draw_ctx,
                    bounds,
                    &unclipped_bounds,
                    url,
                )
            }
            Some(Href::WithFragment(ref frag)) => {
                self.render_node(ctx, acquired_nodes, draw_ctx, bounds, frag)
            }
            _ => Err(FilterError::InvalidInput),
        }
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<commit_msg>Remove obsolete comment<commit_after>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::{Fragment, Href};
use crate::aspect_ratio::AspectRatio;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;
use crate::viewbox::ViewBox;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct FeImage {
    base: Primitive,
    aspect: AspectRatio,
    href: Option<Href>,
}

impl Default for FeImage {
    /// Constructs a new `FeImage` with empty properties.
    #[inline]
    fn default() -> FeImage {
        FeImage {
            base: Primitive::new::<Self>(),
            aspect: AspectRatio::default(),
            href: None,
        }
    }
}

impl FeImage {
    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        draw_ctx: &mut DrawingCtx,
        bounds: Rect,
        fragment: &Fragment,
    ) -> Result<FilterResult, FilterError> {
        let acquired_drawable = acquired_nodes
            .acquire(fragment)
            .map_err(|_| FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();
        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        let image = draw_ctx.draw_node_to_surface(
            &drawable,
            acquired_nodes,
            &cascaded,
            ctx.paffine(),
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let surface = ctx.source_graphic().paint_image(bounds, &image, None)?;

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface,
                bounds: bounds.into(),
            },
        })
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        _draw_ctx: &DrawingCtx,
        bounds: Rect,
        unclipped_bounds: &Rect,
        url: &str,
    ) -> Result<FilterResult, FilterError> {
        // FIXME: translate the error better here
        let image = acquired_nodes
            .lookup_image(url)
            .map_err(|_| FilterError::InvalidInput)?;

        let rect = self.aspect.compute(
            &ViewBox(Rect::from_size(
                f64::from(image.width()),
                f64::from(image.height()),
            )),
            &unclipped_bounds,
        );

        let surface = ctx
            .source_graphic()
            .paint_image(bounds, &image, Some(rect))?;

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface,
                bounds: bounds.into(),
            },
        })
    }
}

impl SetAttributes for FeImage {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        self.base.set_attributes(pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "preserveAspectRatio") => self.aspect = attr.parse(value)?,

                // "path" is used by some older Adobe Illustrator versions
                expanded_name!(xlink "href") | expanded_name!("", "path") => {
                    let href = Href::parse(value)
                        .map_err(ValueErrorKind::from)
                        .attribute(attr)?;

                    self.href = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeImage {
    fn render(
        &self,
        node: &Node,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let bounds_builder = self.base.get_bounds(ctx, node.parent().as_ref())?;
        let bounds = bounds_builder.into_rect(draw_ctx);

        match self.href.as_ref() {
            Some(Href::PlainUrl(url)) => {
                let unclipped_bounds = bounds_builder.into_rect_without_clipping(draw_ctx);
                self.render_external_image(
                    ctx,
                    acquired_nodes,
                    draw_ctx,
                    bounds,
                    &unclipped_bounds,
                    url,
                )
            }
            Some(Href::WithFragment(ref frag)) => {
                self.render_node(ctx, acquired_nodes, draw_ctx, bounds, frag)
            }
            _ => Err(FilterError::InvalidInput),
        }
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>use gltf_derive::Validate;
use serde_derive::{Serialize, Deserialize};
use serde::{de, ser};
use std::fmt;
use crate::validation::{Checked, Validate};
use crate::{extensions, texture, Extras, Index};

/// All valid alpha modes.
pub const VALID_ALPHA_MODES: &'static [&'static str] = &[
    "OPAQUE",
    "MASK",
    "BLEND",
];

/// The alpha rendering mode of a material.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum AlphaMode {
    /// The alpha value is ignored and the rendered output is fully opaque.
    Opaque = 1,

    /// The rendered output is either fully opaque or fully transparent depending on
    /// the alpha value and the specified alpha cutoff value.
    Mask,

    /// The alpha value is used, to determine the transparence of the rendered output.
    /// The alpha cutoff value is ignored.
    Blend,
}

impl ser::Serialize for AlphaMode {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        match *self {
            AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
            AlphaMode::Mask => serializer.serialize_str("MASK"),
            AlphaMode::Blend => serializer.serialize_str("BLEND"),
        }
    }
}

/// The material appearance of a primitive.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Material {
    /// The alpha cutoff value of the material.
    #[serde(rename = "alphaCutoff")]
    //#[cfg_attr(feature = "alphaCutoff", serde(skip_serializing_if = "Option::is_none"))]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub alpha_cutoff: Option<AlphaCutoff>,

    /// The alpha rendering mode of the material.
    ///
    /// The material's alpha rendering mode enumeration specifying the
    /// interpretation of the alpha value of the main factor and texture.
    ///
    /// * In `Opaque` mode (default) the alpha value is ignored and the rendered
    ///   output is fully opaque.
    ///
    /// * In `Mask` mode, the rendered output is either fully opaque or fully
    ///   transparent depending on the alpha value and the specified alpha cutoff
    ///   value.
    ///
    /// * In `Blend` mode, the alpha value is used to composite the source and
    ///   destination areas and the rendered output is combined with the
    ///   background using the normal painting operation (i.e. the Porter and
    ///   Duff over operator).
    #[serde(rename = "alphaMode")]
    pub alpha_mode: Checked<AlphaMode>,

    /// Specifies whether the material is double-sided.
    ///
    /// * When this value is false, back-face culling is enabled.
    ///
    /// * When this value is true, back-face culling is disabled and double sided
    ///   lighting is enabled.
    ///
    /// The back-face must have its normals reversed before the lighting
    /// equation is evaluated.
    #[serde(rename = "doubleSided")]
    pub double_sided: bool,

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
    pub name: Option<String>,

    /// A set of parameter values that are used to define the metallic-roughness
    /// material model from Physically-Based Rendering (PBR) methodology. When not
    /// specified, all the default values of `pbrMetallicRoughness` apply.
    #[serde(default, rename = "pbrMetallicRoughness")]
    pub pbr_metallic_roughness: PbrMetallicRoughness,

    /// A tangent space normal map. The texture contains RGB components in linear
    /// space. Each texel represents the XYZ components of a normal vector in
    /// tangent space. Red [0 to 255] maps to X [-1 to 1]. Green [0 to 255] maps to
    /// Y [-1 to 1]. Blue [128 to 255] maps to Z [1/255 to 1]. The normal vectors
    /// use OpenGL conventions where +X is right and +Y is up. +Z points toward the
    /// viewer.
    #[serde(rename = "normalTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub normal_texture: Option<NormalTexture>,

    /// The occlusion map texture. The occlusion values are sampled from the R
    /// channel. Higher values indicate areas that should receive full indirect
    /// lighting and lower values indicate no indirect lighting. These values are
    /// linear. If other channels are present (GBA), they are ignored for occlusion
    /// calculations.
    #[serde(rename = "occlusionTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub occlusion_texture: Option<OcclusionTexture>,

    /// The emissive map controls the color and intensity of the light being emitted
    /// by the material. This texture contains RGB components in sRGB color space.
    /// If a fourth component (A) is present, it is ignored.
    #[serde(rename = "emissiveTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub emissive_texture: Option<texture::Info>,

    /// The emissive color of the material.
    #[serde(rename = "emissiveFactor")]
    pub emissive_factor: EmissiveFactor,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::Material>,

    /// Optional application specific data.
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct PbrMetallicRoughness {
    /// The material's base color factor.
    #[serde(rename = "baseColorFactor")]
    pub base_color_factor: PbrBaseColorFactor,

    /// The base color texture.
    #[serde(rename = "baseColorTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub base_color_texture: Option<texture::Info>,

    /// The metalness of the material.
    #[serde(rename = "metallicFactor")]
    pub metallic_factor: StrengthFactor,

    /// The roughness of the material.
    ///
    /// * A value of 1.0 means the material is completely rough.
    /// * A value of 0.0 means the material is completely smooth.
    #[serde(rename = "roughnessFactor")]
    pub roughness_factor: StrengthFactor,

    /// The metallic-roughness texture.
    ///
    /// This texture has two components:
    ///
    /// The metalness values are sampled from the B channel.
    /// The roughness values are sampled from the G channel.
    /// These values are linear. If other channels are present (R or A),
    /// they are ignored for metallic-roughness calculations.
    #[serde(rename = "metallicRoughnessTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metallic_roughness_texture: Option<texture::Info>,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::PbrMetallicRoughness>,

    /// Optional application specific data.
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// Defines the normal texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct NormalTexture {
    /// The index of the texture.
    pub index: Index<texture::Texture>,

    /// The scalar multiplier applied to each normal vector of the texture.
    ///
    /// This value is ignored if normalTexture is not specified.
    #[serde(default = "material_normal_texture_scale_default")]
    pub scale: f32,

    /// The set index of the texture's `TEXCOORD` attribute.
    #[serde(default, rename = "texCoord")]
    pub tex_coord: u32,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::NormalTexture>,

    /// Optional application specific data.
    #[serde(default)]
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

fn material_normal_texture_scale_default() -> f32 {
    1.0
}

/// Defines the occlusion texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct OcclusionTexture {
    /// The index of the texture.
    pub index: Index<texture::Texture>,

    /// The scalar multiplier controlling the amount of occlusion applied.
    #[serde(default)]
    pub strength: StrengthFactor,

    /// The set index of the texture's `TEXCOORD` attribute.
    #[serde(default, rename = "texCoord")]
    pub tex_coord: u32,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::OcclusionTexture>,

    /// Optional application specific data.
    #[serde(default)]
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// The alpha cutoff value of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AlphaCutoff(pub f32);

/// The emissive color of a material.
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
pub struct EmissiveFactor(pub [f32; 3]);

/// The base color factor of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrBaseColorFactor(pub [f32; 4]);

/// A number in the inclusive range [0.0, 1.0] with a default value of 1.0.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct StrengthFactor(pub f32);

impl Default for AlphaCutoff {
    fn default() -> Self {
        AlphaCutoff(0.5)
    }
}

impl Validate for AlphaCutoff {}

impl Default for AlphaMode {
    fn default() -> Self {
        AlphaMode::Opaque
    }
}

impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: de::Deserializer<'de>
    {
        struct Visitor;
        impl<'de> de::Visitor<'de> for Visitor {
            type Value = Checked<AlphaMode>;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "any of: {:?}", VALID_ALPHA_MODES)
            }

            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                use self::AlphaMode::*;
                use crate::validation::Checked::*;
                Ok(match value {
                    "OPAQUE" => Valid(Opaque),
                    "MASK" => Valid(Mask),
                    "BLEND" => Valid(Blend),
                    _ => Invalid,
                })
            }
        }
        deserializer.deserialize_str(Visitor)
    }
}

impl Validate for EmissiveFactor {}

impl Default for PbrBaseColorFactor {
    fn default() -> Self {
        PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
    }
}

impl Validate for PbrBaseColorFactor {}

impl Default for StrengthFactor {
    fn default() -> Self {
        StrengthFactor(1.0)
    }
}

impl Validate for StrengthFactor {}
<commit_msg>Fix previously introduced typo in documentation comment.<commit_after>use gltf_derive::Validate;
use serde_derive::{Serialize, Deserialize};
use serde::{de, ser};
use std::fmt;
use crate::validation::{Checked, Validate};
use crate::{extensions, texture, Extras, Index};

/// All valid alpha modes.
pub const VALID_ALPHA_MODES: &'static [&'static str] = &[
    "OPAQUE",
    "MASK",
    "BLEND",
];

/// The alpha rendering mode of a material.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum AlphaMode {
    /// The alpha value is ignored and the rendered output is fully opaque.
    Opaque = 1,

    /// The rendered output is either fully opaque or fully transparent depending on
    /// the alpha value and the specified alpha cutoff value.
    Mask,

    /// The alpha value is used, to determine the transparency of the rendered output.
    /// The alpha cutoff value is ignored.
    Blend,
}

impl ser::Serialize for AlphaMode {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        match *self {
            AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
            AlphaMode::Mask => serializer.serialize_str("MASK"),
            AlphaMode::Blend => serializer.serialize_str("BLEND"),
        }
    }
}

/// The material appearance of a primitive.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Material {
    /// The alpha cutoff value of the material.
    #[serde(rename = "alphaCutoff")]
    //#[cfg_attr(feature = "alphaCutoff", serde(skip_serializing_if = "Option::is_none"))]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub alpha_cutoff: Option<AlphaCutoff>,

    /// The alpha rendering mode of the material.
    ///
    /// The material's alpha rendering mode enumeration specifying the
    /// interpretation of the alpha value of the main factor and texture.
    ///
    /// * In `Opaque` mode (default) the alpha value is ignored and the rendered
    ///   output is fully opaque.
    ///
    /// * In `Mask` mode, the rendered output is either fully opaque or fully
    ///   transparent depending on the alpha value and the specified alpha cutoff
    ///   value.
    ///
    /// * In `Blend` mode, the alpha value is used to composite the source and
    ///   destination areas and the rendered output is combined with the
    ///   background using the normal painting operation (i.e. the Porter and
    ///   Duff over operator).
    #[serde(rename = "alphaMode")]
    pub alpha_mode: Checked<AlphaMode>,

    /// Specifies whether the material is double-sided.
    ///
    /// * When this value is false, back-face culling is enabled.
    ///
    /// * When this value is true, back-face culling is disabled and double sided
    ///   lighting is enabled.
    ///
    /// The back-face must have its normals reversed before the lighting
    /// equation is evaluated.
    #[serde(rename = "doubleSided")]
    pub double_sided: bool,

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
    pub name: Option<String>,

    /// A set of parameter values that are used to define the metallic-roughness
    /// material model from Physically-Based Rendering (PBR) methodology. When not
    /// specified, all the default values of `pbrMetallicRoughness` apply.
    #[serde(default, rename = "pbrMetallicRoughness")]
    pub pbr_metallic_roughness: PbrMetallicRoughness,

    /// A tangent space normal map. The texture contains RGB components in linear
    /// space. Each texel represents the XYZ components of a normal vector in
    /// tangent space. Red [0 to 255] maps to X [-1 to 1]. Green [0 to 255] maps to
    /// Y [-1 to 1]. Blue [128 to 255] maps to Z [1/255 to 1]. The normal vectors
    /// use OpenGL conventions where +X is right and +Y is up. +Z points toward the
    /// viewer.
    #[serde(rename = "normalTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub normal_texture: Option<NormalTexture>,

    /// The occlusion map texture. The occlusion values are sampled from the R
    /// channel. Higher values indicate areas that should receive full indirect
    /// lighting and lower values indicate no indirect lighting. These values are
    /// linear. If other channels are present (GBA), they are ignored for occlusion
    /// calculations.
    #[serde(rename = "occlusionTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub occlusion_texture: Option<OcclusionTexture>,

    /// The emissive map controls the color and intensity of the light being emitted
    /// by the material. This texture contains RGB components in sRGB color space.
    /// If a fourth component (A) is present, it is ignored.
    #[serde(rename = "emissiveTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub emissive_texture: Option<texture::Info>,

    /// The emissive color of the material.
    #[serde(rename = "emissiveFactor")]
    pub emissive_factor: EmissiveFactor,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::Material>,

    /// Optional application specific data.
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct PbrMetallicRoughness {
    /// The material's base color factor.
    #[serde(rename = "baseColorFactor")]
    pub base_color_factor: PbrBaseColorFactor,

    /// The base color texture.
    #[serde(rename = "baseColorTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub base_color_texture: Option<texture::Info>,

    /// The metalness of the material.
    #[serde(rename = "metallicFactor")]
    pub metallic_factor: StrengthFactor,

    /// The roughness of the material.
    ///
    /// * A value of 1.0 means the material is completely rough.
    /// * A value of 0.0 means the material is completely smooth.
    #[serde(rename = "roughnessFactor")]
    pub roughness_factor: StrengthFactor,

    /// The metallic-roughness texture.
    ///
    /// This texture has two components:
    ///
    /// The metalness values are sampled from the B channel.
    /// The roughness values are sampled from the G channel.
    /// These values are linear. If other channels are present (R or A),
    /// they are ignored for metallic-roughness calculations.
    #[serde(rename = "metallicRoughnessTexture")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metallic_roughness_texture: Option<texture::Info>,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::PbrMetallicRoughness>,

    /// Optional application specific data.
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// Defines the normal texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct NormalTexture {
    /// The index of the texture.
    pub index: Index<texture::Texture>,

    /// The scalar multiplier applied to each normal vector of the texture.
    ///
    /// This value is ignored if normalTexture is not specified.
    #[serde(default = "material_normal_texture_scale_default")]
    pub scale: f32,

    /// The set index of the texture's `TEXCOORD` attribute.
    #[serde(default, rename = "texCoord")]
    pub tex_coord: u32,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::NormalTexture>,

    /// Optional application specific data.
    #[serde(default)]
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

fn material_normal_texture_scale_default() -> f32 {
    1.0
}

/// Defines the occlusion texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct OcclusionTexture {
    /// The index of the texture.
    pub index: Index<texture::Texture>,

    /// The scalar multiplier controlling the amount of occlusion applied.
    #[serde(default)]
    pub strength: StrengthFactor,

    /// The set index of the texture's `TEXCOORD` attribute.
    #[serde(default, rename = "texCoord")]
    pub tex_coord: u32,

    /// Extension specific data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extensions: Option<extensions::material::OcclusionTexture>,

    /// Optional application specific data.
    #[serde(default)]
    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
    pub extras: Extras,
}

/// The alpha cutoff value of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AlphaCutoff(pub f32);

/// The emissive color of a material.
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
pub struct EmissiveFactor(pub [f32; 3]);

/// The base color factor of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrBaseColorFactor(pub [f32; 4]);

/// A number in the inclusive range [0.0, 1.0] with a default value of 1.0.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct StrengthFactor(pub f32);

impl Default for AlphaCutoff {
    fn default() -> Self {
        AlphaCutoff(0.5)
    }
}

impl Validate for AlphaCutoff {}

impl Default for AlphaMode {
    fn default() -> Self {
        AlphaMode::Opaque
    }
}

impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: de::Deserializer<'de>
    {
        struct Visitor;
        impl<'de> de::Visitor<'de> for Visitor {
            type Value = Checked<AlphaMode>;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "any of: {:?}", VALID_ALPHA_MODES)
            }

            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                use self::AlphaMode::*;
                use crate::validation::Checked::*;
                Ok(match value {
                    "OPAQUE" => Valid(Opaque),
                    "MASK" => Valid(Mask),
                    "BLEND" => Valid(Blend),
                    _ => Invalid,
                })
            }
        }
        deserializer.deserialize_str(Visitor)
    }
}

impl Validate for EmissiveFactor {}

impl Default for PbrBaseColorFactor {
    fn default() -> Self {
        PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
    }
}

impl Validate for PbrBaseColorFactor {}

impl Default for StrengthFactor {
    fn default() -> Self {
        StrengthFactor(1.0)
    }
}

impl Validate for StrengthFactor {}
<|endoftext|>