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

use gtk::{
    ButtonExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::{Horizontal, Vertical};
use relm::{Component, ContainerWidget, Widget};
use relm_derive::{Msg, widget};

use self::CounterMsg::*;
use self::Msg::*;

pub struct CounterModel {
    counter: i32,
}

#[derive(Msg)]
pub enum CounterMsg {
    Decrement,
    Increment,
}

#[widget]
impl Widget for Counter {
    fn model() -> CounterModel {
        CounterModel {
            counter: 0,
        }
    }

    fn update(&mut self, event: CounterMsg) {
        match event {
            Decrement => self.model.counter -= 1,
            Increment => self.model.counter += 1,
        }
    }

    view! {
        gtk::Box {
            orientation: Vertical,
            gtk::Button {
                label: "+",
                widget_name: "inc_button",
                clicked => Increment,
            },
            gtk::Label {
                label: "0",
                widget_name: "label",
                text: &self.model.counter.to_string(),
            },
            gtk::Button {
                label: "-",
                clicked => Decrement,
            },
        }
    }
}

#[derive(Msg)]
pub enum Msg {
    Add,
    Quit,
    Remove,
}

pub struct Model {
    counters: Vec<Component<Counter>>,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counters: vec![],
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Add => {
                let widget = self.widgets.hbox.add_widget::<Counter>(());
                self.model.counters.push(widget);
            },
            Quit => gtk::main_quit(),
            Remove => {
                if let Some(counter) = self.model.counters.pop() {
                    self.widgets.hbox.remove_widget(counter);
                }
            },
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                #[name="hbox"]
                gtk::Box {
                    orientation: Horizontal,
                },
                #[name="add_button"]
                gtk::Button {
                    label: "Add",
                    clicked => Add,
                },
                #[name="remove_button"]
                gtk::Button {
                    label: "Remove",
                    clicked => Remove,
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}

#[cfg(test)]
mod tests {
    use gtk::{Button, ContainerExt, Label, LabelExt};

    use gtk_test::{assert_text, find_child_by_name};
    use relm_test::click;

    use crate::Win;

    #[test]
    fn root_widget() {
        let (_component, _, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
        let hbox = &widgets.hbox;
        let add_button = &widgets.add_button;
        let remove_button = &widgets.remove_button;

        assert_eq!(hbox.get_children().len(), 0);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 1);

        let widget1 = &hbox.get_children()[0];
        let inc_button1: Button = find_child_by_name(widget1, "inc_button").expect("inc button");
        let label1: Label = find_child_by_name(widget1, "label").expect("label");
        assert_text!(label1, 0);

        click(&inc_button1);
        assert_text!(label1, 1);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 2);

        let widget2 = &hbox.get_children()[1];
        let inc_button2: Button = find_child_by_name(widget2, "inc_button").expect("inc button");
        let label2: Label = find_child_by_name(widget2, "label").expect("label");
        assert_text!(label2, 0);

        click(&inc_button2);
        assert_text!(label2, 1);

        click(&inc_button1);
        assert_text!(label1, 2);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 3);

        let widget3 = &hbox.get_children()[2];
        let inc_button3: Button = find_child_by_name(widget3, "inc_button").expect("inc button");
        let label3: Label = find_child_by_name(widget3, "label").expect("label");
        assert_text!(label3, 0);

        click(&inc_button3);
        assert_text!(label3, 1);

        click(&inc_button2);
        assert_text!(label2, 2);

        click(&inc_button1);
        assert_text!(label1, 3);

        click(remove_button);
        assert_eq!(hbox.get_children().len(), 2);

        click(&inc_button1);
        assert_text!(label1, 4);

        click(&inc_button2);
        assert_text!(label2, 3);

        click(remove_button);
        assert_eq!(hbox.get_children().len(), 1);

        click(&inc_button1);
        assert_text!(label1, 5);

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

use std::sync::atomic::{AtomicUsize, Ordering};

use gtk::{
    ButtonExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::{Horizontal, Vertical};
use relm::{Component, ContainerWidget, Widget};
use relm_derive::{Msg, widget};

use self::CounterMsg::*;
use self::Msg::*;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub struct CounterModel {
    counter: i32,
}

#[derive(Msg)]
pub enum CounterMsg {
    Decrement,
    Increment,
}

#[widget]
impl Widget for Counter {
    fn model() -> CounterModel {
        COUNTER.fetch_add(1, Ordering::SeqCst);
        CounterModel {
            counter: 0,
        }
    }

    fn update(&mut self, event: CounterMsg) {
        match event {
            Decrement => self.model.counter -= 1,
            Increment => self.model.counter += 1,
        }
    }

    view! {
        gtk::Box {
            orientation: Vertical,
            gtk::Button {
                label: "+",
                widget_name: "inc_button",
                clicked => Increment,
            },
            gtk::Label {
                label: "0",
                widget_name: "label",
                text: &self.model.counter.to_string(),
            },
            gtk::Button {
                label: "-",
                clicked => Decrement,
            },
        }
    }
}

impl Drop for Counter {
    fn drop(&mut self) {
        COUNTER.fetch_sub(1, Ordering::SeqCst);
    }
}

#[derive(Msg)]
pub enum Msg {
    Add,
    Quit,
    Remove,
}

pub struct Model {
    counters: Vec<Component<Counter>>,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counters: vec![],
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Add => {
                let widget = self.widgets.hbox.add_widget::<Counter>(());
                self.model.counters.push(widget);
            },
            Quit => gtk::main_quit(),
            Remove => {
                if let Some(counter) = self.model.counters.pop() {
                    self.widgets.hbox.remove_widget(counter);
                }
            },
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                #[name="hbox"]
                gtk::Box {
                    orientation: Horizontal,
                },
                #[name="add_button"]
                gtk::Button {
                    label: "Add",
                    clicked => Add,
                },
                #[name="remove_button"]
                gtk::Button {
                    label: "Remove",
                    clicked => Remove,
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}

#[cfg(test)]
mod tests {
    use std::sync::atomic::Ordering;

    use gtk::{Button, ContainerExt, Label, LabelExt};

    use gtk_test::{assert_text, find_child_by_name};
    use relm_test::click;

    use crate::{Win, COUNTER};

    #[test]
    fn root_widget() {
        let (_component, _, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
        let hbox = &widgets.hbox;
        let add_button = &widgets.add_button;
        let remove_button = &widgets.remove_button;

        assert_eq!(hbox.get_children().len(), 0);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 0);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 1);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 1);

        let widget1 = &hbox.get_children()[0];
        let inc_button1: Button = find_child_by_name(widget1, "inc_button").expect("inc button");
        let label1: Label = find_child_by_name(widget1, "label").expect("label");
        assert_text!(label1, 0);

        click(&inc_button1);
        assert_text!(label1, 1);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 2);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 2);

        let widget2 = &hbox.get_children()[1];
        let inc_button2: Button = find_child_by_name(widget2, "inc_button").expect("inc button");
        let label2: Label = find_child_by_name(widget2, "label").expect("label");
        assert_text!(label2, 0);

        click(&inc_button2);
        assert_text!(label2, 1);

        click(&inc_button1);
        assert_text!(label1, 2);

        click(add_button);
        assert_eq!(hbox.get_children().len(), 3);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 3);

        let widget3 = &hbox.get_children()[2];
        let inc_button3: Button = find_child_by_name(widget3, "inc_button").expect("inc button");
        let label3: Label = find_child_by_name(widget3, "label").expect("label");
        assert_text!(label3, 0);

        click(&inc_button3);
        assert_text!(label3, 1);

        click(&inc_button2);
        assert_text!(label2, 2);

        click(&inc_button1);
        assert_text!(label1, 3);

        click(remove_button);
        assert_eq!(hbox.get_children().len(), 2);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 2);

        click(&inc_button1);
        assert_text!(label1, 4);

        click(&inc_button2);
        assert_text!(label2, 3);

        click(remove_button);
        assert_eq!(hbox.get_children().len(), 1);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 1);

        click(&inc_button1);
        assert_text!(label1, 5);

        click(remove_button);
        assert_eq!(hbox.get_children().len(), 0);
        assert_eq!(COUNTER.load(Ordering::SeqCst), 0);
    }
}
<|endoftext|>


<commit_before>// This does practically the same thing that TryFrom<&str> does.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
use std::str::FromStr;

#[derive(Debug)]
struct Person {
    name: String,
    age: usize,
}

// I AM NOT DONE
// Steps:
// 1. If the length of the provided string is 0, then return an error
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return an error
// Otherwise, then return a Result of a Person object
impl FromStr for Person {
    type Err = String;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
    }
}

fn main() {
    let p = "Mark,20".parse::<Person>().unwrap();
    println!("{:?}", p);
}

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

    #[test]
    fn empty_input() {
        assert!("".parse::<Person>().is_err());
    }
    #[test]
    fn good_input() {
        assert!("John,32".parse::<Person>().is_ok());
    }
    #[test]
    #[should_panic]
    fn missing_age() {
        "John".parse::<Person>().unwrap();
    }
}<commit_msg>test: Add missing test case for from_str exercise<commit_after>// This does practically the same thing that TryFrom<&str> does.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
use std::str::FromStr;

#[derive(Debug)]
struct Person {
    name: String,
    age: usize,
}

// I AM NOT DONE
// Steps:
// 1. If the length of the provided string is 0, then return an error
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return an error
// Otherwise, then return a Result of a Person object
impl FromStr for Person {
    type Err = String;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
    }
}

fn main() {
    let p = "Mark,20".parse::<Person>().unwrap();
    println!("{:?}", p);
}

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

    #[test]
    fn empty_input() {
        assert!("".parse::<Person>().is_err());
    }
    #[test]
    fn good_input() {
        let p = "John,32".parse::<Person>();
        assert!(p.is_ok());
        let p = p.unwrap();
        assert_eq!(p.name, "John");
        assert_eq!(p.age, 32);
    }
    #[test]
    #[should_panic]
    fn missing_age() {
        "John".parse::<Person>().unwrap();
    }
}<|endoftext|>


<commit_before>//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::lazy::SyncLazy;
use std::path::PathBuf;
use walkdir::WalkDir;

use crate::clippy_project_root;

// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
    Some(v) => v.into(),
    None => env::current_dir().unwrap().join("target"),
});

pub fn bless() {
    let test_dirs = [
        clippy_project_root().join("tests").join("ui"),
        clippy_project_root().join("tests").join("ui-toml"),
        clippy_project_root().join("tests").join("ui-cargo"),
    ];
    for test_dir in &test_dirs {
        WalkDir::new(test_dir)
            .into_iter()
            .filter_map(Result::ok)
            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
            .for_each(|f| {
                let test_name = f.path().strip_prefix(test_dir).unwrap();

                update_reference_file(f.path().with_extension("stdout"), test_name.with_extension("stdout"));
                update_reference_file(f.path().with_extension("stderr"), test_name.with_extension("stderr"));
                update_reference_file(f.path().with_extension("fixed"), test_name.with_extension("fixed"));
            });
    }
}

fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) {
    let test_output_path = build_dir().join(test_name);
    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();

    // If compiletest did not write any changes during the test run,
    // we don't have to update anything
    if !test_output_path.exists() {
        return;
    }

    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
    let reference_file = fs::read(&reference_file_path).unwrap_or_default();

    if test_output_file != reference_file {
        // If a test run caused an output file to change, update the reference file
        println!("updating {}", &relative_reference_file_path.display());
        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");

        // We need to re-read the file now because it was potentially updated from copying
        let reference_file = fs::read(&reference_file_path).unwrap_or_default();

        if reference_file.is_empty() {
            // If we copied over an empty output file, we remove the now empty reference file
            println!("removing {}", &relative_reference_file_path.display());
            fs::remove_file(reference_file_path).expect("Could not remove reference file");
        }
    }
}

fn build_dir() -> PathBuf {
    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
    let mut path = PathBuf::new();
    path.push(CARGO_TARGET_DIR.clone());
    path.push(profile);
    path.push("test_build_base");
    path
}
<commit_msg>s/test_dir/test_suite_dir<commit_after>//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::lazy::SyncLazy;
use std::path::PathBuf;
use walkdir::WalkDir;

use crate::clippy_project_root;

// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
    Some(v) => v.into(),
    None => env::current_dir().unwrap().join("target"),
});

pub fn bless() {
    let test_suite_dirs = [
        clippy_project_root().join("tests").join("ui"),
        clippy_project_root().join("tests").join("ui-toml"),
        clippy_project_root().join("tests").join("ui-cargo"),
    ];
    for test_suite_dir in &test_suite_dirs {
        WalkDir::new(test_suite_dir)
            .into_iter()
            .filter_map(Result::ok)
            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
            .for_each(|f| {
                let test_name = f.path().strip_prefix(test_suite_dir).unwrap();

                update_reference_file(f.path().with_extension("stdout"), test_name.with_extension("stdout"));
                update_reference_file(f.path().with_extension("stderr"), test_name.with_extension("stderr"));
                update_reference_file(f.path().with_extension("fixed"), test_name.with_extension("fixed"));
            });
    }
}

fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) {
    let test_output_path = build_dir().join(test_name);
    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();

    // If compiletest did not write any changes during the test run,
    // we don't have to update anything
    if !test_output_path.exists() {
        return;
    }

    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
    let reference_file = fs::read(&reference_file_path).unwrap_or_default();

    if test_output_file != reference_file {
        // If a test run caused an output file to change, update the reference file
        println!("updating {}", &relative_reference_file_path.display());
        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");

        // We need to re-read the file now because it was potentially updated from copying
        let reference_file = fs::read(&reference_file_path).unwrap_or_default();

        if reference_file.is_empty() {
            // If we copied over an empty output file, we remove the now empty reference file
            println!("removing {}", &relative_reference_file_path.display());
            fs::remove_file(reference_file_path).expect("Could not remove reference file");
        }
    }
}

fn build_dir() -> PathBuf {
    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
    let mut path = PathBuf::new();
    path.push(CARGO_TARGET_DIR.clone());
    path.push(profile);
    path.push("test_build_base");
    path
}
<|endoftext|>


<commit_before>use num::cast::*;
use angle::*;
use vec::{Vec3, Vec2, Vec4};

///
/// Triganomic functions
///
/// http://en.wikipedia.org/wiki/Trigonometric_functions
///
priv trait Trig<T> {
    pure fn sin() -> T;
    pure fn cos() -> T;
    pure fn tan() -> T;
}

#[inline(always)] pub pure fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
#[inline(always)] pub pure fn cos<T:Trig<R>, R>(theta: &T) -> R { theta.cos() }
#[inline(always)] pub pure fn tan<T:Trig<R>, R>(theta: &T) -> R { theta.tan() }

priv impl<T:Copy Num NumCast> Radians<T>: Trig<T> {
    #[inline(always)] pure fn sin() -> T { cast(f64::sin(cast(*self))) }
    #[inline(always)] pure fn cos() -> T { cast(f64::cos(cast(*self))) }
    #[inline(always)] pure fn tan() -> T { cast(f64::tan(cast(*self))) }
}

///
/// Inverse triganomic functions
///
/// http://en.wikipedia.org/wiki/Inverse_trigonometric_functions
///
pub trait InvTrig {
    pure fn asin() -> Radians<self>;
    pure fn acos() -> Radians<self>;
    pure fn atan() -> Radians<self>;
}

#[inline(always)] pub pure fn asin<T:InvTrig>(x: &T) -> Radians<T> { x.asin() }
#[inline(always)] pub pure fn acos<T:InvTrig>(x: &T) -> Radians<T> { x.acos() }
#[inline(always)] pub pure fn atan<T:InvTrig>(x: &T) -> Radians<T> { x.atan() }

pub impl f32: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f32> { Radians(f32::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f32> { Radians(f32::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f32> { Radians(f32::atan(self)) }
}

pub impl f64: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f64> { Radians(f64::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f64> { Radians(f64::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f64> { Radians(f64::atan(self)) }
}

pub impl float: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<float> { Radians(f64::asin(cast(self)).to_float()) }
    #[inline(always)] pure fn acos() -> Radians<float> { Radians(f64::acos(cast(self)).to_float()) }
    #[inline(always)] pure fn atan() -> Radians<float> { Radians(f64::atan(cast(self)).to_float()) }
}

///
/// Hyperbolic functions
///
/// http://en.wikipedia.org/wiki/Hyperbolic_function
///
pub trait Hyp {
    pure fn sinh() -> self;
    pure fn cosh() -> self;
    pure fn tanh() -> self;
    // pure fn asinh() -> self;
    // pure fn acosh() -> self;
    // pure fn atanh() -> self;
}

#[inline(always)] pub pure fn sinh<T:Hyp>(x: &T) -> T { x.sinh() }
#[inline(always)] pub pure fn cosh<T:Hyp>(x: &T) -> T { x.cosh() }
#[inline(always)] pub pure fn tanh<T:Hyp>(x: &T) -> T { x.tanh() }

pub impl f32: Hyp {
    #[inline(always)] pure fn sinh() -> f32 { f32::sinh(self) }
    #[inline(always)] pure fn cosh() -> f32 { f32::cosh(self) }
    #[inline(always)] pure fn tanh() -> f32 { f32::tanh(self) }
}

pub impl f64: Hyp {
    #[inline(always)] pure fn sinh() -> f64 { f64::sinh(self) }
    #[inline(always)] pure fn cosh() -> f64 { f64::cosh(self) }
    #[inline(always)] pure fn tanh() -> f64 { f64::tanh(self) }
}

pub impl float: Hyp {
    #[inline(always)] pure fn sinh() -> float { cast(f64::sinh(cast(self))) }
    #[inline(always)] pure fn cosh() -> float { cast(f64::cosh(cast(self))) }
    #[inline(always)] pure fn tanh() -> float { cast(f64::tanh(cast(self))) }
}

// pub impl <T:Copy Trig> Vec2<T>: Trig {
//     #[inline(always)]
//     pure fn sin() -> Vec2<T> {
//         Vec2::new(sin(&self[0]),
//                   sin(&self[1]))
//     }

//     #[inline(always)]
//     pure fn cos() -> Vec2<T> {
//         Vec2::new(cos(&self[0]),
//                   cos(&self[1]))
//     }

//     #[inline(always)]
//     pure fn tan() -> Vec2<T> {
//         Vec2::new(tan(&self[0]),
//                   tan(&self[1]))
//     }

//     #[inline(always)]
//     pure fn asin() -> Vec2<T> {
//         Vec2::new(asin(&self[0]),
//                   asin(&self[1]))
//     }

//     #[inline(always)]
//     pure fn acos() -> Vec2<T> {
//         Vec2::new(acos(&self[0]),
//                   acos(&self[1]))
//     }

//     #[inline(always)]
//     pure fn atan() -> Vec2<T> {
//         Vec2::new(atan(&self[0]),
//                   atan(&self[1]))
//     }

//     #[inline(always)]
//     pure fn sinh() -> Vec2<T> {
//         Vec2::new(sinh(&self[0]),
//                   sinh(&self[1]))
//     }

//     #[inline(always)]
//     pure fn cosh() -> Vec2<T> {
//         Vec2::new(cosh(&self[0]),
//                   cosh(&self[1]))
//     }

//     #[inline(always)]
//     pure fn tanh() -> Vec2<T> {
//         Vec2::new(tanh(&self[0]),
//                   tanh(&self[1]))
//     }
// }

// pub impl <T:Copy Trig> Vec3<T>: Trig {
//     #[inline(always)]
//     pure fn sin() -> Vec3<T> {
//         Vec3::new(sin(&self[0]),
//                   sin(&self[1]),
//                   sin(&self[2]))
//     }

//     #[inline(always)]
//     pure fn cos() -> Vec3<T> {
//         Vec3::new(cos(&self[0]),
//                   cos(&self[1]),
//                   cos(&self[2]))
//     }

//     #[inline(always)]
//     pure fn tan() -> Vec3<T> {
//         Vec3::new(tan(&self[0]),
//                   tan(&self[1]),
//                   tan(&self[2]))
//     }

//     #[inline(always)]
//     pure fn asin() -> Vec3<T> {
//         Vec3::new(asin(&self[0]),
//                   asin(&self[1]),
//                   asin(&self[2]))
//     }

//     #[inline(always)]
//     pure fn acos() -> Vec3<T> {
//         Vec3::new(acos(&self[0]),
//                   acos(&self[1]),
//                   acos(&self[2]))
//     }

//     #[inline(always)]
//     pure fn atan() -> Vec3<T> {
//         Vec3::new(atan(&self[0]),
//                   atan(&self[1]),
//                   atan(&self[2]))
//     }

//     #[inline(always)]
//     pure fn sinh() -> Vec3<T> {
//         Vec3::new(sinh(&self[0]),
//                   sinh(&self[1]),
//                   sinh(&self[2]))
//     }

//     #[inline(always)]
//     pure fn cosh() -> Vec3<T> {
//         Vec3::new(cosh(&self[0]),
//                   cosh(&self[1]),
//                   cosh(&self[2]))
//     }

//     #[inline(always)]
//     pure fn tanh() -> Vec3<T> {
//         Vec3::new(tanh(&self[0]),
//                   tanh(&self[1]),
//                   tanh(&self[2]))
//     }
// }

// pub impl <T:Copy Trig> Vec4<T>: Trig  {
//     #[inline(always)]
//     pure fn sin() -> Vec4<T> {
//         Vec4::new(sin(&self[0]),
//                   sin(&self[1]),
//                   sin(&self[2]),
//                   sin(&self[3]))
//     }

//     #[inline(always)]
//     pure fn cos() -> Vec4<T> {
//         Vec4::new(cos(&self[0]),
//                   cos(&self[1]),
//                   cos(&self[2]),
//                   cos(&self[3]))
//     }

//     #[inline(always)]
//     pure fn tan() -> Vec4<T> {
//         Vec4::new(tan(&self[0]),
//                   tan(&self[1]),
//                   tan(&self[2]),
//                   tan(&self[3]))
//     }

//     #[inline(always)]
//     pure fn asin() -> Vec4<T> {
//         Vec4::new(asin(&self[0]),
//                   asin(&self[1]),
//                   asin(&self[2]),
//                   asin(&self[3]))
//     }

//     #[inline(always)]
//     pure fn acos() -> Vec4<T> {
//         Vec4::new(acos(&self[0]),
//                   acos(&self[1]),
//                   acos(&self[2]),
//                   acos(&self[3]))
//     }

//     #[inline(always)]
//     pure fn atan() -> Vec4<T> {
//         Vec4::new(atan(&self[0]),
//                   atan(&self[1]),
//                   atan(&self[2]),
//                   atan(&self[3]))
//     }

//     #[inline(always)]
//     pure fn sinh() -> Vec4<T> {
//         Vec4::new(sinh(&self[0]),
//                   sinh(&self[1]),
//                   sinh(&self[2]),
//                   sinh(&self[3]))
//     }

//     #[inline(always)]
//     pure fn cosh() -> Vec4<T> {
//         Vec4::new(cosh(&self[0]),
//                   cosh(&self[1]),
//                   cosh(&self[2]),
//                   cosh(&self[3]))
//     }

//     #[inline(always)]
//     pure fn tanh() -> Vec4<T> {
//         Vec4::new(tanh(&self[0]),
//                   tanh(&self[1]),
//                   tanh(&self[2]),
//                   tanh(&self[3]))
//     }
// }<commit_msg>Implement Trig and Hyp for vector types<commit_after>use num::cast::*;
use angle::*;
use vec::{Vec3, Vec2, Vec4};

///
/// Triganomic functions
///
/// http://en.wikipedia.org/wiki/Trigonometric_functions
///
priv trait Trig<T> {
    pure fn sin() -> T;
    pure fn cos() -> T;
    pure fn tan() -> T;
}

#[inline(always)] pub pure fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
#[inline(always)] pub pure fn cos<T:Trig<R>, R>(theta: &T) -> R { theta.cos() }
#[inline(always)] pub pure fn tan<T:Trig<R>, R>(theta: &T) -> R { theta.tan() }

priv impl<T:Copy Num NumCast> Radians<T>: Trig<T> {
    #[inline(always)] pure fn sin() -> T { cast(f64::sin(cast(*self))) }
    #[inline(always)] pure fn cos() -> T { cast(f64::cos(cast(*self))) }
    #[inline(always)] pure fn tan() -> T { cast(f64::tan(cast(*self))) }
}

pub impl<T:Copy Num NumCast> Vec2<Radians<T>>: Trig<Vec2<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec2<T> {
        Vec2::new(sin(&self[0]),
                  sin(&self[1]))
    }

    #[inline(always)]
    pure fn cos() -> Vec2<T> {
        Vec2::new(cos(&self[0]),
                  cos(&self[1]))
    }

    #[inline(always)]
    pure fn tan() -> Vec2<T> {
        Vec2::new(tan(&self[0]),
                  tan(&self[1]))
    }
}

pub impl<T:Copy Num NumCast> Vec3<Radians<T>>: Trig<Vec3<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec3<T> {
        Vec3::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]))
    }

    #[inline(always)]
    pure fn cos() -> Vec3<T> {
        Vec3::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]))
    }

    #[inline(always)]
    pure fn tan() -> Vec3<T> {
        Vec3::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]))
    }
}

pub impl<T:Copy Num NumCast> Vec4<Radians<T>>: Trig<Vec4<T>>  {
    #[inline(always)]
    pure fn sin() -> Vec4<T> {
        Vec4::new(sin(&self[0]),
                  sin(&self[1]),
                  sin(&self[2]),
                  sin(&self[3]))
    }

    #[inline(always)]
    pure fn cos() -> Vec4<T> {
        Vec4::new(cos(&self[0]),
                  cos(&self[1]),
                  cos(&self[2]),
                  cos(&self[3]))
    }

    #[inline(always)]
    pure fn tan() -> Vec4<T> {
        Vec4::new(tan(&self[0]),
                  tan(&self[1]),
                  tan(&self[2]),
                  tan(&self[3]))
    }
}

///
/// Inverse triganomic functions
///
/// http://en.wikipedia.org/wiki/Inverse_trigonometric_functions
///
pub trait InvTrig {
    pure fn asin() -> Radians<self>;
    pure fn acos() -> Radians<self>;
    pure fn atan() -> Radians<self>;
}

#[inline(always)] pub pure fn asin<T:InvTrig>(x: &T) -> Radians<T> { x.asin() }
#[inline(always)] pub pure fn acos<T:InvTrig>(x: &T) -> Radians<T> { x.acos() }
#[inline(always)] pub pure fn atan<T:InvTrig>(x: &T) -> Radians<T> { x.atan() }

pub impl f32: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f32> { Radians(f32::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f32> { Radians(f32::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f32> { Radians(f32::atan(self)) }
}

pub impl f64: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<f64> { Radians(f64::asin(self)) }
    #[inline(always)] pure fn acos() -> Radians<f64> { Radians(f64::acos(self)) }
    #[inline(always)] pure fn atan() -> Radians<f64> { Radians(f64::atan(self)) }
}

pub impl float: InvTrig {
    #[inline(always)] pure fn asin() -> Radians<float> { Radians(f64::asin(cast(self)).to_float()) }
    #[inline(always)] pure fn acos() -> Radians<float> { Radians(f64::acos(cast(self)).to_float()) }
    #[inline(always)] pure fn atan() -> Radians<float> { Radians(f64::atan(cast(self)).to_float()) }
}

///
/// Hyperbolic functions
///
/// http://en.wikipedia.org/wiki/Hyperbolic_function
///
pub trait Hyp {
    pure fn sinh() -> self;
    pure fn cosh() -> self;
    pure fn tanh() -> self;
    // pure fn asinh() -> self;
    // pure fn acosh() -> self;
    // pure fn atanh() -> self;
}

#[inline(always)] pub pure fn sinh<T:Hyp>(x: &T) -> T { x.sinh() }
#[inline(always)] pub pure fn cosh<T:Hyp>(x: &T) -> T { x.cosh() }
#[inline(always)] pub pure fn tanh<T:Hyp>(x: &T) -> T { x.tanh() }

pub impl f32: Hyp {
    #[inline(always)] pure fn sinh() -> f32 { f32::sinh(self) }
    #[inline(always)] pure fn cosh() -> f32 { f32::cosh(self) }
    #[inline(always)] pure fn tanh() -> f32 { f32::tanh(self) }
}

pub impl f64: Hyp {
    #[inline(always)] pure fn sinh() -> f64 { f64::sinh(self) }
    #[inline(always)] pure fn cosh() -> f64 { f64::cosh(self) }
    #[inline(always)] pure fn tanh() -> f64 { f64::tanh(self) }
}

pub impl float: Hyp {
    #[inline(always)] pure fn sinh() -> float { cast(f64::sinh(cast(self))) }
    #[inline(always)] pure fn cosh() -> float { cast(f64::cosh(cast(self))) }
    #[inline(always)] pure fn tanh() -> float { cast(f64::tanh(cast(self))) }
}

pub impl <T:Copy Hyp> Vec2<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec2<T> {
        Vec2::new(sinh(&self[0]),
                  sinh(&self[1]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec2<T> {
        Vec2::new(cosh(&self[0]),
                  cosh(&self[1]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec2<T> {
        Vec2::new(tanh(&self[0]),
                  tanh(&self[1]))
    }
}

pub impl <T:Copy Hyp> Vec3<T>: Hyp {
    #[inline(always)]
    pure fn sinh() -> Vec3<T> {
        Vec3::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec3<T> {
        Vec3::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec3<T> {
        Vec3::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]))
    }
}

pub impl <T:Copy Hyp> Vec4<T>: Hyp  {
    #[inline(always)]
    pure fn sinh() -> Vec4<T> {
        Vec4::new(sinh(&self[0]),
                  sinh(&self[1]),
                  sinh(&self[2]),
                  sinh(&self[3]))
    }

    #[inline(always)]
    pure fn cosh() -> Vec4<T> {
        Vec4::new(cosh(&self[0]),
                  cosh(&self[1]),
                  cosh(&self[2]),
                  cosh(&self[3]))
    }

    #[inline(always)]
    pure fn tanh() -> Vec4<T> {
        Vec4::new(tanh(&self[0]),
                  tanh(&self[1]),
                  tanh(&self[2]),
                  tanh(&self[3]))
    }
}<|endoftext|>


<commit_before>extern crate regex;

use colored::*;
use std::process::exit;
use regex::RegexSet;
use nom::IResult;
use std::path::PathBuf;

pub fn file_contents_to_regex(file: &str, file_path: &PathBuf) -> RegexSet {
    let processed_vec: Vec<&str> = process_to_vector(file);
    let processed_str: String = processed_vec.join("");
    let lines = processed_str.split_whitespace();

    debugln!("{:?}", lines.clone().collect::<Vec<&str>>());

    let maybe_set = RegexSet::new(lines);
    if let Ok(s) = maybe_set {
        s
    }
    else {
        eprintln!("{}: failed to parse .gitignore at {:?}, ignoring", "Warning".yellow(), file_path);
        let empty: Vec<&str> = Vec::new();
        RegexSet::new(empty)
            .expect("Error creating regex from empty vector")
    }
}

pub fn process_to_vector(input: &str) -> Vec<&str> {
    match process(input) {
        IResult::Done(_, result) => result,
        _ => { eprintln!("{}: Failed to parse gitignore", "Error".red()) ; exit(0xf001) }
    }
}

named!(process<&str, Vec<&str>>,
    do_parse!(
        opt!(first_line) >>
        r: many0!(options) >>
        (r)
    )
);

named!(options<&str, &str>,
    alt!(
        gitignore_comment |
        is_not!("*?.#") |
        parse_asterix |
        parse_period |
        parse_questionmark |
        parse_not_comment
    )
);

named!(parse_not_comment<&str, &str>,
    do_parse!(
        //tag!("#") >>
        is_not!("\n#") >>
        ("#")
    )
);

named!(first_line<&str, &str>,
    do_parse!(
        tag!("#") >>
        is_not!("\n") >>
        tag!("\n") >>
        ("\n")
    )
);

named!(gitignore_comment<&str, &str>,
    do_parse!(
        tag!("\n#") >>
        is_not!("\n") >>
        tag!("\n") >>
        ("\n")
    )
);

named!(parse_period<&str, &str>,
    do_parse!(
        tag!(".") >>
        ("\\.")
    )
);

named!(parse_asterix<&str, &str>,
    do_parse!(
        tag!("*") >>
        opt!(do_parse!(tag!("\n") >> eof!() >> (""))) >>
        (".*")
    )
);

named!(parse_questionmark<&str, &str>,
    do_parse!(
        tag!("?") >>
        opt!(do_parse!(tag!("\n") >> eof!() >> (""))) >>
        (".")
    )
);
<commit_msg>partially fixed a pernicious bug in the gitignore parser<commit_after>extern crate regex;

use colored::*;
use std::process::exit;
use regex::RegexSet;
use nom::IResult;
use std::path::PathBuf;

pub fn file_contents_to_regex(file: &str, file_path: &PathBuf) -> RegexSet {
    let processed_vec: Vec<&str> = process_to_vector(file);
    let processed_str: String = processed_vec.join("");
    let lines = processed_str.split_whitespace();

    debugln!("{:?}", lines.clone().collect::<Vec<&str>>());

    let maybe_set = RegexSet::new(lines);
    if let Ok(s) = maybe_set {
        s
    }
    else {
        eprintln!("{}: failed to parse .gitignore at {:?}, ignoring", "Warning".yellow(), file_path);
        let empty: Vec<&str> = Vec::new();
        RegexSet::new(empty)
            .expect("Error creating regex from empty vector")
    }
}

pub fn process_to_vector(input: &str) -> Vec<&str> {
    match process(input) {
        IResult::Done(_, result) => result,
        _ => { eprintln!("{}: Failed to parse gitignore", "Error".red()) ; exit(0xf001) }
    }
}

named!(process<&str, Vec<&str>>,
    do_parse!(
        opt!(first_line) >>
        r: many0!(options) >>
        (r)
    )
);

named!(options<&str, &str>,
    alt!(
        gitignore_comment |
        is_not!("*?.#") |
        parse_asterix |
        parse_period |
        parse_questionmark |
        parse_not_comment |
        gitignore_comment
    )
);

named!(parse_not_comment<&str, &str>,
    do_parse!(
        //tag!("#") >>
        is_not!("\n#") >>
        ("#")
    )
);

named!(first_line<&str, &str>,
    do_parse!(
        tag!("#") >>
        is_not!("\n") >>
        tag!("\n") >>
        ("\n")
    )
);

named!(gitignore_comment<&str, &str>,
    do_parse!(
        tag!("\n#") >>
        is_not!("\n") >>
        tag!("\n") >>
        ("\n")
    )
);

named!(parse_period<&str, &str>,
    do_parse!(
        tag!(".") >>
        ("\\.")
    )
);

named!(parse_asterix<&str, &str>,
    do_parse!(
        tag!("*") >>
        opt!(do_parse!(tag!("\n") >> eof!() >> (""))) >>
        (".*")
    )
);

named!(parse_questionmark<&str, &str>,
    do_parse!(
        tag!("?") >>
        opt!(do_parse!(tag!("\n") >> eof!() >> (""))) >>
        (".")
    )
);
<|endoftext|>


<commit_before>use specs::*;

use amq_protocol_types::*;
use serde_json::Value;

/* Modified version of AMQProtocolDefinition to handle deserialization */
#[derive(Debug, Deserialize)]
pub struct _AMQProtocolDefinition {
    name:          String,
    #[serde(rename="major-version")]
    major_version: u8,
    #[serde(rename="minor-version")]
    minor_version: u8,
    revision:      u8,
    port:          u32,
    copyright:     Vec<String>,
    domains:       Vec<_AMQPDomain>,
    constants:     Vec<AMQPConstant>,
    classes:       Vec<_AMQPClass>,
}

impl _AMQProtocolDefinition {
    pub fn to_specs(self) -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          self.name,
            major_version: self.major_version,
            minor_version: self.minor_version,
            revision:      self.revision,
            port:          self.port,
            copyright:     self.copyright,
            domains:       self.domains.iter().map(|domain| domain.to_specs()).collect(),
            constants:     self.constants,
            classes:       self.classes.iter().map(|klass| klass.to_specs()).collect(),
        }
    }
}

/* Defined as a two-elems array in the spec */
#[derive(Debug, Deserialize)]
struct _AMQPDomain(String, _AMQPType);

impl _AMQPDomain {
    fn to_specs(&self) -> AMQPDomain {
        AMQPDomain {
            name:      self.0.clone(),
            amqp_type: self.1.to_specs(),
        }
    }
}

/* Subset of AMQPType used in specs for deserialization */
#[derive(Debug, Deserialize)]
enum _AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl _AMQPType {
    fn to_specs(&self) -> AMQPType {
        match *self {
            _AMQPType::Bit       => AMQPType::Boolean,
            /* FIXME: Should those be Int or UInt ? */
            _AMQPType::Octet     => AMQPType::ShortShortInt,
            _AMQPType::Short     => AMQPType::ShortInt,
            _AMQPType::Long      => AMQPType::LongInt,
            _AMQPType::LongLong  => AMQPType::LongLongInt,
            _AMQPType::ShortStr  => AMQPType::ShortString,
            _AMQPType::LongStr   => AMQPType::LongString,
            _AMQPType::Table     => AMQPType::FieldTable,
            _AMQPType::Timestamp => AMQPType::Timestamp,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPClass {
    id:         u8,
    methods:    Vec<_AMQPMethod>,
    name:       String,
    properties: Option<Vec<_AMQPProperty>>,
}

impl _AMQPClass {
    fn to_specs(&self) -> AMQPClass {
        AMQPClass {
            id:         self.id,
            methods:    self.methods.iter().map(|method| method.to_specs()).collect(),
            name:       self.name.clone(),
            properties: match self.properties {
                Some(ref properties) => Some(properties.iter().map(|prop| prop.to_specs()).collect()),
                None                 => None,
            },
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPMethod {
    id:          u8,
    arguments:   Vec<_AMQPArgument>,
    name:        String,
    synchronous: Option<bool>,
}

impl _AMQPMethod {
    fn to_specs(&self) -> AMQPMethod {
        AMQPMethod {
            id:          self.id,
            arguments:   self.arguments.iter().map(|arg| arg.to_specs()).collect(),
            name:        self.name.clone(),
            synchronous: self.synchronous,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPArgument {
    #[serde(rename="type")]
    amqp_type:     Option<_AMQPType>,
    name:          String,
    #[serde(rename="default-value")]
    default_value: Option<Value>,
    domain:        Option<String>,
}

impl _AMQPArgument {
    fn to_specs(&self) -> AMQPArgument {
        AMQPArgument {
            amqp_type:     match self.amqp_type {
                Some(ref amqp_type) => Some(amqp_type.to_specs()),
                None                => None,
            },
            name:          self.name.clone(),
            default_value: self.default_value.clone(),
            domain:        self.domain.clone(),
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPProperty {
    #[serde(rename="type")]
    amqp_type: _AMQPType,
    name:      String,
}

impl _AMQPProperty {
    fn to_specs(&self) -> AMQPProperty {
        AMQPProperty {
            amqp_type: self.amqp_type.to_specs(),
            name:      self.name.clone(),
        }
    }
}
<commit_msg>codegen: fix types parsed from specs<commit_after>use specs::*;

use amq_protocol_types::*;
use serde_json::Value;

/* Modified version of AMQProtocolDefinition to handle deserialization */
#[derive(Debug, Deserialize)]
pub struct _AMQProtocolDefinition {
    name:          String,
    #[serde(rename="major-version")]
    major_version: u8,
    #[serde(rename="minor-version")]
    minor_version: u8,
    revision:      u8,
    port:          u32,
    copyright:     Vec<String>,
    domains:       Vec<_AMQPDomain>,
    constants:     Vec<AMQPConstant>,
    classes:       Vec<_AMQPClass>,
}

impl _AMQProtocolDefinition {
    pub fn to_specs(self) -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          self.name,
            major_version: self.major_version,
            minor_version: self.minor_version,
            revision:      self.revision,
            port:          self.port,
            copyright:     self.copyright,
            domains:       self.domains.iter().map(|domain| domain.to_specs()).collect(),
            constants:     self.constants,
            classes:       self.classes.iter().map(|klass| klass.to_specs()).collect(),
        }
    }
}

/* Defined as a two-elems array in the spec */
#[derive(Debug, Deserialize)]
struct _AMQPDomain(String, _AMQPType);

impl _AMQPDomain {
    fn to_specs(&self) -> AMQPDomain {
        AMQPDomain {
            name:      self.0.clone(),
            amqp_type: self.1.to_specs(),
        }
    }
}

/* Subset of AMQPType used in specs for deserialization */
#[derive(Debug, Deserialize)]
enum _AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl _AMQPType {
    fn to_specs(&self) -> AMQPType {
        match *self {
            _AMQPType::Bit       => AMQPType::Boolean,
            _AMQPType::Octet     => AMQPType::ShortShortUInt,
            _AMQPType::Short     => AMQPType::ShortUInt,
            _AMQPType::Long      => AMQPType::LongUInt,
            _AMQPType::LongLong  => AMQPType::LongLongUInt,
            _AMQPType::ShortStr  => AMQPType::ShortString,
            _AMQPType::LongStr   => AMQPType::LongString,
            _AMQPType::Table     => AMQPType::FieldTable,
            _AMQPType::Timestamp => AMQPType::Timestamp,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPClass {
    id:         u8,
    methods:    Vec<_AMQPMethod>,
    name:       String,
    properties: Option<Vec<_AMQPProperty>>,
}

impl _AMQPClass {
    fn to_specs(&self) -> AMQPClass {
        AMQPClass {
            id:         self.id,
            methods:    self.methods.iter().map(|method| method.to_specs()).collect(),
            name:       self.name.clone(),
            properties: match self.properties {
                Some(ref properties) => Some(properties.iter().map(|prop| prop.to_specs()).collect()),
                None                 => None,
            },
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPMethod {
    id:          u8,
    arguments:   Vec<_AMQPArgument>,
    name:        String,
    synchronous: Option<bool>,
}

impl _AMQPMethod {
    fn to_specs(&self) -> AMQPMethod {
        AMQPMethod {
            id:          self.id,
            arguments:   self.arguments.iter().map(|arg| arg.to_specs()).collect(),
            name:        self.name.clone(),
            synchronous: self.synchronous,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPArgument {
    #[serde(rename="type")]
    amqp_type:     Option<_AMQPType>,
    name:          String,
    #[serde(rename="default-value")]
    default_value: Option<Value>,
    domain:        Option<String>,
}

impl _AMQPArgument {
    fn to_specs(&self) -> AMQPArgument {
        AMQPArgument {
            amqp_type:     match self.amqp_type {
                Some(ref amqp_type) => Some(amqp_type.to_specs()),
                None                => None,
            },
            name:          self.name.clone(),
            default_value: self.default_value.clone(),
            domain:        self.domain.clone(),
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPProperty {
    #[serde(rename="type")]
    amqp_type: _AMQPType,
    name:      String,
}

impl _AMQPProperty {
    fn to_specs(&self) -> AMQPProperty {
        AMQPProperty {
            amqp_type: self.amqp_type.to_specs(),
            name:      self.name.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::genmsg;
use proc_macro::TokenStream;
use quote::quote;
use std::env;
use std::path::Path;

pub fn depend_on_messages(
    messages: &[&str],
    internal: bool,
    ignore_bad_messages: bool,
) -> TokenStream {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let ros_package_paths = env::var("ROS_PACKAGE_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(ros_package_paths.iter())
        .chain(extra_paths.iter())
        .map(String::as_str)
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(ignore_bad_messages, paths.as_slice(), messages)
        .unwrap_or_else(|r| panic!("{}", r))
        .token_stream(&if internal {
            quote! { crate:: }
        } else {
            quote! { rosrust:: }
        });
    (quote! {#output}).into()
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}
<commit_msg>Remove extra line added<commit_after>use crate::genmsg;
use proc_macro::TokenStream;
use quote::quote;
use std::env;
use std::path::Path;

pub fn depend_on_messages(
    messages: &[&str],
    internal: bool,
    ignore_bad_messages: bool,
) -> TokenStream {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let ros_package_paths = env::var("ROS_PACKAGE_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(ros_package_paths.iter())
        .chain(extra_paths.iter())
        .map(String::as_str)
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(ignore_bad_messages, paths.as_slice(), messages)
        .unwrap_or_else(|r| panic!("{}", r))
        .token_stream(&if internal {
            quote! { crate:: }
        } else {
            quote! { rosrust:: }
        });
    (quote! {#output}).into()
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}
<|endoftext|>


<commit_before>use crate::convert::Convert;
use std::default::Default;
use std::hash::{Hasher};
use arrayref::*;

use const_random::const_random;

///Const random provides randomzied keys with no runtime cost.
const DEFAULT_KEYS: [u64;2] = [const_random!(u64), const_random!(u64)];
///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

/// Provides a [Hasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// Constructs a new [AHasher] with compile time generated constants keys.
/// So the key will be the same from one instance to another,
/// but different from build to the next. So if it is possible for a potential
/// attacker to have access to your compiled binary it would be better
/// to specify keys generated at runtime.
///
/// # Examples
///
/// ```
/// use ahash::AHasher;
/// use std::hash::Hasher;
///
/// let mut hasher_1 = AHasher::default();
/// let mut hasher_2 = AHasher::default();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher { buffer: DEFAULT_KEYS }
    }
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] ^= length;
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() > 8 {
            if data.len() > 16 {
                if data.len() > 128 {
                    let mut par_block: u128 = self.buffer.convert();
                    par_block ^= PAD;
                    while data.len() > 128 {
                        let (b1, rest) = data.split_at(16);
                        let b1: u128 = (*as_array!(b1, 16)).convert();
                        par_block = aeshash(par_block, b1);
                        data = rest;
                        let (b2, rest) = data.split_at(16);
                        let b2: u128 = (*as_array!(b2, 16)).convert();
                        self.buffer = aeshash(self.buffer.convert(), b2).convert();
                        data = rest;
                    }
                    self.buffer = aeshash(par_block, self.buffer.convert()).convert();
                }
                while data.len() > 32 {
                    //len 33-128
                    let (block, rest) = data.split_at(16);
                    let block: u128 = (*as_array!(block, 16)).convert();
                    self.buffer = aeshash(self.buffer.convert(),block).convert();
                    data = rest;
                }
                //len 17-32
                let block = (*array_ref!(data, 0, 16)).convert();
                self.buffer = aeshash(self.buffer.convert(),block).convert();
                let block = (*array_ref!(data, data.len()-16, 16)).convert();
                self.buffer = aeshash(self.buffer.convert(),block).convert();
            } else {
                //len 9-16
                let block: [u64; 2] = [(*array_ref!(data, 0, 8)).convert(),
                    (*array_ref!(data, data.len()-8, 8)).convert()];
                self.buffer = aeshash(self.buffer.convert(),block.convert()).convert();
            }
        } else {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    let block: [u32; 2] = [(*array_ref!(data, 0, 4)).convert(),
                        (*array_ref!(data, data.len()-4, 4)).convert()];
                    let block: [u64;2] = [block[1] as u64, block[0] as u64];
                    self.buffer = aeshash(self.buffer.convert(),block.convert()).convert()
                } else {
                    //len 2-3
                    let block: [u16; 2] = [(*array_ref!(data, 0, 2)).convert(),
                        (*array_ref!(data, data.len()-2, 2)).convert()];
                    let block: u32 = block.convert();
                    self.buffer = aeshash(self.buffer.convert(), block as u128).convert();
                }
            } else {
                if data.len() > 0 {
                    //len 1
                    self.buffer = aeshash(self.buffer.convert(), data[0] as u128).convert();
                }
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use std::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>I've convinced myself the xor was not needed.<commit_after>use crate::convert::Convert;
use std::default::Default;
use std::hash::{Hasher};
use arrayref::*;

use const_random::const_random;

///Const random provides randomzied keys with no runtime cost.
const DEFAULT_KEYS: [u64;2] = [const_random!(u64), const_random!(u64)];
///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

/// Provides a [Hasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// Constructs a new [AHasher] with compile time generated constants keys.
/// So the key will be the same from one instance to another,
/// but different from build to the next. So if it is possible for a potential
/// attacker to have access to your compiled binary it would be better
/// to specify keys generated at runtime.
///
/// # Examples
///
/// ```
/// use ahash::AHasher;
/// use std::hash::Hasher;
///
/// let mut hasher_1 = AHasher::default();
/// let mut hasher_2 = AHasher::default();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher { buffer: DEFAULT_KEYS }
    }
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] ^= length;
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() > 8 {
            if data.len() > 16 {
                if data.len() > 128 {
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 128 {
                        let (b1, rest) = data.split_at(16);
                        let b1: u128 = (*as_array!(b1, 16)).convert();
                        par_block = aeshash(par_block, b1);
                        data = rest;
                        let (b2, rest) = data.split_at(16);
                        let b2: u128 = (*as_array!(b2, 16)).convert();
                        self.buffer = aeshash(self.buffer.convert(), b2).convert();
                        data = rest;
                    }
                    self.buffer = aeshash(self.buffer.convert(), par_block).convert();
                }
                while data.len() > 32 {
                    //len 33-128
                    let (block, rest) = data.split_at(16);
                    let block: u128 = (*as_array!(block, 16)).convert();
                    self.buffer = aeshash(self.buffer.convert(),block).convert();
                    data = rest;
                }
                //len 17-32
                let block = (*array_ref!(data, 0, 16)).convert();
                self.buffer = aeshash(self.buffer.convert(),block).convert();
                let block = (*array_ref!(data, data.len()-16, 16)).convert();
                self.buffer = aeshash(self.buffer.convert(),block).convert();
            } else {
                //len 9-16
                let block: [u64; 2] = [(*array_ref!(data, 0, 8)).convert(),
                    (*array_ref!(data, data.len()-8, 8)).convert()];
                self.buffer = aeshash(self.buffer.convert(),block.convert()).convert();
            }
        } else {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    let block: [u32; 2] = [(*array_ref!(data, 0, 4)).convert(),
                        (*array_ref!(data, data.len()-4, 4)).convert()];
                    let block: [u64;2] = [block[1] as u64, block[0] as u64];
                    self.buffer = aeshash(self.buffer.convert(),block.convert()).convert()
                } else {
                    //len 2-3
                    let block: [u16; 2] = [(*array_ref!(data, 0, 2)).convert(),
                        (*array_ref!(data, data.len()-2, 2)).convert()];
                    let block: u32 = block.convert();
                    self.buffer = aeshash(self.buffer.convert(), block as u128).convert();
                }
            } else {
                if data.len() > 0 {
                    //len 1
                    self.buffer = aeshash(self.buffer.convert(), data[0] as u128).convert();
                }
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use std::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>


<commit_before>//! Encode a `BlockContent` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_prop, concat, elem, elem_empty, json,
    EncodeContext, ToHtml,
};
use html_escape::encode_safe;
use stencila_schema::*;

impl ToHtml for BlockContent {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        match self {
            BlockContent::Claim(node) => node.to_html(slot, context),
            BlockContent::CodeBlock(node) => node.to_html(slot, context),
            BlockContent::CodeChunk(node) => node.to_html(slot, context),
            BlockContent::Collection(node) => node.to_html(slot, context),
            BlockContent::Figure(node) => node.to_html(slot, context),
            BlockContent::Heading(node) => node.to_html(slot, context),
            BlockContent::Include(node) => node.to_html(slot, context),
            BlockContent::List(node) => node.to_html(slot, context),
            BlockContent::MathBlock(node) => node.to_html(slot, context),
            BlockContent::Paragraph(node) => node.to_html(slot, context),
            BlockContent::QuoteBlock(node) => node.to_html(slot, context),
            BlockContent::Table(node) => node.to_html(slot, context),
            BlockContent::ThematicBreak(node) => node.to_html(slot, context),
        }
    }
}

impl ToHtml for ClaimSimple {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "pre",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &json(self),
        )
    }
}

impl ToHtml for CodeBlock {
    /// Encode a [`CodeBlock`] as HTML
    ///
    /// The `programming_language` is encoded as both a `class` attribute and a `<meta>` element.
    /// The `<meta>` element is for Microdata and Stencila WebComponent compatibility.
    /// The `class` follows the recommendation of [HTML5 spec](https://html.spec.whatwg.org/#the-code-element)
    /// to "use the class attribute, e.g. by adding a class prefixed with "language-" to the element."
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let (class, meta) = match &self.programming_language {
            Some(programming_language) => (
                attr("class", &["language-", programming_language].concat()),
                elem_empty(
                    "meta",
                    &[
                        attr_itemprop("programming_language"),
                        attr("content", programming_language),
                    ],
                ),
            ),
            None => ("".to_string(), "".to_string()),
        };

        let text = elem(
            "code",
            &[attr_itemprop("text"), class],
            &encode_safe(&self.text),
        );

        elem(
            "pre",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[meta, text].concat(),
        )
    }
}

impl ToHtml for CodeChunk {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            None => String::new(),
            Some(label) => elem("label", &[attr_prop("label")], label),
        };

        let caption = match &self.caption {
            None => String::new(),
            Some(boxed) => match &**boxed {
                CodeChunkCaption::String(string) => string.clone(),
                CodeChunkCaption::VecBlockContent(content) => content.to_html("", context),
            },
        };

        let text = elem("pre", &[attr("slot", "text")], &encode_safe(&self.text));

        let outputs = match &self.outputs {
            None => String::new(),
            Some(outputs) => elem(
                "pre",
                &[attr("slot", "outputs")],
                &outputs.to_html("", context),
            ),
        };

        elem(
            "figure",
            &[attr_itemtype::<Self>()],
            &[
                label,
                elem(
                    "stencila-code-chunk",
                    &[
                        attr_prop(slot),
                        attr_itemtype::<Self>(),
                        attr_id(&self.id),
                        attr("programming-language", &self.programming_language),
                    ],
                    &[text, outputs].concat(),
                ),
                caption,
            ]
            .concat(),
        )
    }
}

impl ToHtml for CollectionSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "ol",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &concat(&self.parts, |part| {
                elem("li", &[], &part.to_html("", context))
            }),
        )
    }
}

impl ToHtml for FigureSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            None => String::new(),
            Some(label) => elem("label", &[attr_prop("label")], label),
        };

        let content = match &self.content {
            None => String::new(),
            Some(nodes) => nodes.to_html("", context),
        };

        let caption = match self.caption.as_deref() {
            None => String::new(),
            Some(caption) => elem(
                "figcaption",
                &[attr_prop("caption")],
                &match caption {
                    FigureCaption::String(string) => encode_safe(&string.clone()).to_string(),
                    FigureCaption::VecBlockContent(content) => content.to_html("", context),
                },
            ),
        };

        elem(
            "figure",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[label, content, caption].concat(),
        )
    }
}

impl ToHtml for Heading {
    /// Encode a `Heading` node to a `<h2>`, `<h3>` etc element.
    ///
    /// > Generally, it is a best practice to ensure that the beginning of a
    /// > page's main content starts with a h1 element, and also to ensure
    /// > that the page contains only one h1 element.
    /// > From https://dequeuniversity.com/rules/axe/3.5/page-has-heading-one
    ///
    /// This codec follows that recommendation and reserves `<h1>` for the
    /// `title` property of a creative work.
    ///
    /// In rare cases that there is no content in the heading, return an empty
    /// text node to avoid the 'Heading tag found with no content' accessibility error.
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let depth = match &self.depth {
            Some(depth) => std::cmp::min(*depth + 1, 6),
            None => 2,
        };

        elem(
            &["h", &depth.to_string()].concat(),
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for Include {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let content = self
            .content
            .as_ref()
            .map_or_else(|| "".to_string(), |content| content.to_html("", context));

        elem(
            "div",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &content,
        )
    }
}

impl ToHtml for List {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let tag = match &self.order {
            Some(ListOrder::Ascending) => "ol",
            _ => "ul",
        };

        elem(
            tag,
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self
                .items
                .iter()
                .map(|item| item.to_html("", context))
                .collect::<Vec<String>>()
                .concat(),
        )
    }
}

impl ToHtml for ListItem {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let checkbox = self.is_checked.map(|is_checked| match is_checked {
            true => InlineContent::String("☑ ".to_string()),
            false => InlineContent::String("☐ ".to_string()),
        });

        let content = match &self.content {
            Some(content) => match content {
                ListItemContent::VecInlineContent(inlines) => match checkbox {
                    Some(checkbox) => [vec![checkbox], inlines.clone()]
                        .concat()
                        .to_html("", context),
                    None => inlines.to_html("", context),
                },
                ListItemContent::VecBlockContent(blocks) => match checkbox {
                    Some(checkbox) => {
                        // Check box is only added if the first block is a paragraph
                        if let Some(BlockContent::Paragraph(paragraph)) = blocks.first() {
                            let mut paragraph = paragraph.clone();
                            paragraph.content.insert(0, checkbox);
                            [
                                paragraph.to_html("", context),
                                concat(&blocks[1..], |block| block.to_html("", context)),
                            ]
                            .concat()
                        } else {
                            blocks.to_html("", context)
                        }
                    }
                    None => blocks.to_html("", context),
                },
            },
            None => "".to_string(),
        };

        elem(
            "li",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &content,
        )
    }
}

impl ToHtml for MathBlock {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "pre",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &encode_safe(&self.text),
        )
    }
}

impl ToHtml for Paragraph {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "p",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for QuoteBlock {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "blockquote",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

/// Encode a table as HTML
///
/// Previously this function split the table cell's into `thead`, `tbody` and `tfoot` sections.
/// However, that interferes with resolving cell addresses in the DOM, so we reverted to a
/// simpler approach of placing all cell into `tbody`
impl ToHtml for TableSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            None => String::new(),
            Some(label) => elem("label", &[attr_prop("label")], label),
        };

        let caption = match self.caption.as_deref() {
            None => String::new(),
            Some(caption) => elem(
                "div",
                &[attr_prop("caption")],
                &match caption {
                    TableCaption::String(string) => encode_safe(&string.clone()).to_string(),
                    TableCaption::VecBlockContent(content) => content.to_html("", context),
                },
            ),
        };

        let caption = elem("caption", &[], &[label, caption].concat());

        let body = elem(
            "tbody",
            &[attr_prop("rows")],
            &concat(&self.rows, |row| row.to_html(slot, context)),
        );

        elem(
            "table",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[caption, body].concat(),
        )
    }
}

impl ToHtml for TableRow {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let cells = concat(&self.cells, |cell| {
            let tag = match &cell.cell_type {
                Some(cell_type) => match cell_type {
                    TableCellCellType::Header => "th",
                    TableCellCellType::Data => "td",
                },

                None => match &self.row_type {
                    Some(TableRowRowType::Header) | Some(TableRowRowType::Footer) => "th",
                    _ => "td",
                },
            };

            let content = match &cell.content {
                None => String::new(),
                Some(content) => match content {
                    TableCellContent::VecInlineContent(nodes) => nodes.to_html("", context),
                    TableCellContent::VecBlockContent(nodes) => nodes.to_html("", context),
                },
            };

            elem(tag, &[attr_itemtype::<TableCell>()], &content)
        });

        elem(
            "tr",
            &[
                attr_prop(slot),
                attr_itemtype::<TableRow>(),
                attr_id(&self.id),
            ],
            &cells,
        )
    }
}

impl ToHtml for ThematicBreak {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem_empty(
            "hr",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
        )
    }
}
<commit_msg>chore(HTML encoding): Revise encoding of code chunks<commit_after>//! Encode a `BlockContent` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_prop, attr_slot, concat, elem, elem_empty,
    elem_meta, json, nothing, EncodeContext, ToHtml,
};
use html_escape::encode_safe;
use stencila_schema::*;

impl ToHtml for BlockContent {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        match self {
            BlockContent::Claim(node) => node.to_html(slot, context),
            BlockContent::CodeBlock(node) => node.to_html(slot, context),
            BlockContent::CodeChunk(node) => node.to_html(slot, context),
            BlockContent::Collection(node) => node.to_html(slot, context),
            BlockContent::Figure(node) => node.to_html(slot, context),
            BlockContent::Heading(node) => node.to_html(slot, context),
            BlockContent::Include(node) => node.to_html(slot, context),
            BlockContent::List(node) => node.to_html(slot, context),
            BlockContent::MathBlock(node) => node.to_html(slot, context),
            BlockContent::Paragraph(node) => node.to_html(slot, context),
            BlockContent::QuoteBlock(node) => node.to_html(slot, context),
            BlockContent::Table(node) => node.to_html(slot, context),
            BlockContent::ThematicBreak(node) => node.to_html(slot, context),
        }
    }
}

impl ToHtml for ClaimSimple {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "pre",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &json(self),
        )
    }
}

impl ToHtml for CodeBlock {
    /// Encode a [`CodeBlock`] as HTML
    ///
    /// The `programming_language` is encoded as both a `class` attribute and a `<meta>` element.
    /// The `<meta>` element is for Microdata and Stencila WebComponent compatibility.
    /// The `class` follows the recommendation of [HTML5 spec](https://html.spec.whatwg.org/#the-code-element)
    /// to "use the class attribute, e.g. by adding a class prefixed with "language-" to the element."
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let (lang_class, lang_meta) = match &self.programming_language {
            Some(programming_language) => (
                attr("class", &["language-", programming_language].concat()),
                elem_meta("programmingLanguage", programming_language),
            ),
            None => (nothing(), nothing()),
        };

        let text = elem(
            "code",
            &[attr_itemprop("text"), lang_class],
            &encode_safe(&self.text),
        );

        elem(
            "pre",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[lang_meta, text].concat(),
        )
    }
}

impl ToHtml for CodeChunk {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            Some(label) => elem("label", &[attr_prop("label"), attr_slot("label")], label),
            None => nothing(),
        };

        let text = elem(
            "pre",
            &[attr_prop("text"), attr_slot("text")],
            &encode_safe(&self.text),
        );

        let lang_attr = attr("data-programminglanguage", &self.programming_language);
        let lang_meta = elem_meta("programmingLanguage", &self.programming_language);

        let outputs = match &self.outputs {
            Some(outputs) => elem(
                "div",
                &[attr_prop("outputs"), attr_slot("outputs")],
                &outputs.to_html("", context),
            ),
            None => nothing(),
        };

        let errors = match &self.errors {
            Some(errors) => elem(
                "div",
                &[attr_prop("errors"), attr_slot("errors")],
                &errors.to_html("", context),
            ),
            None => nothing(),
        };

        let caption = match &self.caption {
            Some(boxed) => {
                let content = match &**boxed {
                    CodeChunkCaption::String(caption) => caption.clone(),
                    CodeChunkCaption::VecBlockContent(caption) => caption.to_html("", context),
                };
                elem(
                    "figcaption",
                    &[attr_prop("caption"), attr_slot("caption")],
                    &content,
                )
            }
            None => nothing(),
        };

        elem(
            "stencila-code-chunk",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                lang_attr,
            ],
            &[label, lang_meta, text, outputs, errors, caption].concat(),
        )
    }
}

impl ToHtml for CodeError {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let error_message = elem("span", &[attr_prop("errorMessage")], &self.error_message);

        let error_type = match &self.error_type {
            None => nothing(),
            Some(error_type) => elem("span", &[attr_prop("errorType")], error_type),
        };

        let stack_trace = match &self.stack_trace {
            None => nothing(),
            Some(stack_trace) => elem("pre", &[attr_prop("stackTrace")], stack_trace),
        };

        elem(
            "div",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[error_message, error_type, stack_trace].concat(),
        )
    }
}

impl ToHtml for CollectionSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "ol",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &concat(&self.parts, |part| {
                elem("li", &[], &part.to_html("", context))
            }),
        )
    }
}

impl ToHtml for FigureSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            None => nothing(),
            Some(label) => elem("label", &[attr_prop("label")], label),
        };

        let content = match &self.content {
            None => nothing(),
            Some(nodes) => nodes.to_html("", context),
        };

        let caption = match self.caption.as_deref() {
            None => nothing(),
            Some(caption) => elem(
                "figcaption",
                &[attr_prop("caption")],
                &match caption {
                    FigureCaption::String(string) => encode_safe(&string.clone()).to_string(),
                    FigureCaption::VecBlockContent(content) => content.to_html("", context),
                },
            ),
        };

        elem(
            "figure",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[label, content, caption].concat(),
        )
    }
}

impl ToHtml for Heading {
    /// Encode a `Heading` node to a `<h2>`, `<h3>` etc element.
    ///
    /// > Generally, it is a best practice to ensure that the beginning of a
    /// > page's main content starts with a h1 element, and also to ensure
    /// > that the page contains only one h1 element.
    /// > From https://dequeuniversity.com/rules/axe/3.5/page-has-heading-one
    ///
    /// This codec follows that recommendation and reserves `<h1>` for the
    /// `title` property of a creative work.
    ///
    /// In rare cases that there is no content in the heading, return an empty
    /// text node to avoid the 'Heading tag found with no content' accessibility error.
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let depth = match &self.depth {
            Some(depth) => std::cmp::min(*depth + 1, 6),
            None => 2,
        };

        elem(
            &["h", &depth.to_string()].concat(),
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for Include {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let content = self
            .content
            .as_ref()
            .map_or_else(|| "".to_string(), |content| content.to_html("", context));

        elem(
            "div",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &content,
        )
    }
}

impl ToHtml for List {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let tag = match &self.order {
            Some(ListOrder::Ascending) => "ol",
            _ => "ul",
        };

        elem(
            tag,
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self
                .items
                .iter()
                .map(|item| item.to_html("", context))
                .collect::<Vec<String>>()
                .concat(),
        )
    }
}

impl ToHtml for ListItem {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let checkbox = self.is_checked.map(|is_checked| match is_checked {
            true => InlineContent::String("☑ ".to_string()),
            false => InlineContent::String("☐ ".to_string()),
        });

        let content = match &self.content {
            Some(content) => match content {
                ListItemContent::VecInlineContent(inlines) => match checkbox {
                    Some(checkbox) => [vec![checkbox], inlines.clone()]
                        .concat()
                        .to_html("", context),
                    None => inlines.to_html("", context),
                },
                ListItemContent::VecBlockContent(blocks) => match checkbox {
                    Some(checkbox) => {
                        // Check box is only added if the first block is a paragraph
                        if let Some(BlockContent::Paragraph(paragraph)) = blocks.first() {
                            let mut paragraph = paragraph.clone();
                            paragraph.content.insert(0, checkbox);
                            [
                                paragraph.to_html("", context),
                                concat(&blocks[1..], |block| block.to_html("", context)),
                            ]
                            .concat()
                        } else {
                            blocks.to_html("", context)
                        }
                    }
                    None => blocks.to_html("", context),
                },
            },
            None => "".to_string(),
        };

        elem(
            "li",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &content,
        )
    }
}

impl ToHtml for MathBlock {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "pre",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &encode_safe(&self.text),
        )
    }
}

impl ToHtml for Paragraph {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "p",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for QuoteBlock {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "blockquote",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}

/// Encode a table as HTML
///
/// Previously this function split the table cell's into `thead`, `tbody` and `tfoot` sections.
/// However, that interferes with resolving cell addresses in the DOM, so we reverted to a
/// simpler approach of placing all cell into `tbody`
impl ToHtml for TableSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let label = match &self.label {
            None => nothing(),
            Some(label) => elem("label", &[attr_prop("label")], label),
        };

        let caption = match self.caption.as_deref() {
            None => nothing(),
            Some(caption) => elem(
                "div",
                &[attr_prop("caption")],
                &match caption {
                    TableCaption::String(string) => encode_safe(&string.clone()).to_string(),
                    TableCaption::VecBlockContent(content) => content.to_html("", context),
                },
            ),
        };

        let caption = elem("caption", &[], &[label, caption].concat());

        let body = elem(
            "tbody",
            &[attr_prop("rows")],
            &concat(&self.rows, |row| row.to_html(slot, context)),
        );

        elem(
            "table",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &[caption, body].concat(),
        )
    }
}

impl ToHtml for TableRow {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let cells = concat(&self.cells, |cell| {
            let tag = match &cell.cell_type {
                Some(cell_type) => match cell_type {
                    TableCellCellType::Header => "th",
                    TableCellCellType::Data => "td",
                },

                None => match &self.row_type {
                    Some(TableRowRowType::Header) | Some(TableRowRowType::Footer) => "th",
                    _ => "td",
                },
            };

            let content = match &cell.content {
                None => nothing(),
                Some(content) => match content {
                    TableCellContent::VecInlineContent(nodes) => nodes.to_html("", context),
                    TableCellContent::VecBlockContent(nodes) => nodes.to_html("", context),
                },
            };

            elem(tag, &[attr_itemtype::<TableCell>()], &content)
        });

        elem(
            "tr",
            &[
                attr_prop(slot),
                attr_itemtype::<TableRow>(),
                attr_id(&self.id),
            ],
            &cells,
        )
    }
}

impl ToHtml for ThematicBreak {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem_empty(
            "hr",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
        )
    }
}
<|endoftext|>