<commit_before>//! Functions for parsing `json_typegen` macro invocations and their arguments
//!
//! Requires the "option-parsing" feature

use syn;
use syn::parse::{boolean, ident, string};
use synom::{alt, call, named, punct, IResult};

use crate::hints::Hint;
use crate::options::{ImportStyle, Options, OutputMode, StringTransform};

#[derive(PartialEq, Debug)]
pub struct MacroInput {
    pub name: String,
    pub sample_source: String,
    pub options: Options,
}

macro_rules! fail {
    ($base:expr, $input:expr) => {
        return Err(format!(
            "{}, but remaining input was '{}'",
            $base,
            $input.trim()
        ));
    };
}

named!(string_or_ident -> String,
    alt!(
        ident => { |ident: syn::Ident| ident.to_string() }
        |
        string => { |lit: syn::StrLit| lit.value }
    )
);

named!(comma_or_closing_brace -> &str,
    alt!(punct!(",") | punct!("}"))
);

/// Parses a full `json_typegen` macro invocation. E.g. something like
/// `json_typegen!("Foo", "http://example.com/sample.json", { deny_unknown_fields });`
pub fn full_macro(input: &str) -> Result<MacroInput, String> {
    let input = input.trim();

    let prefix = "json_typegen!(";
    if !input.starts_with(prefix) {
        fail!("Unable to parse macro. Expected 'json_typegen!('", input)
    }

    let suffix = ");";
    if !input.ends_with(suffix) {
        fail!("Unable to parse macro. Expected it to end with ');'", input)
    }

    let input = &input[prefix.len()..input.len() - suffix.len()].trim();

    macro_input(input)
}

/// Parses the arguments to a `json_typegen` macro invocation. E.g. something like
/// `"Foo", "http://example.com/sample.json", { deny_unknown_fields }`
pub fn macro_input(input: &str) -> Result<MacroInput, String> {
    let (input, name) = match string(input) {
        IResult::Done(input, lit) => (input, lit.value),
        IResult::Error => fail!("First argument must be a string literal", input),
    };

    let input = skip(input, ",", "Expected a comma after first argument")?;

    let (input, sample_source) = match string(input) {
        IResult::Done(input, lit) => (input, lit.value),
        IResult::Error => fail!("Second argument must be a string literal", input),
    };

    let default_options = Options::macro_default();

    if input.trim().is_empty() {
        return Ok(MacroInput {
            name,
            sample_source,
            options: default_options,
        });
    }

    let input = skip(
        input,
        ",",
        "Expected a comma or end of input after second argument",
    )?;

    let options = match string(input) {
        IResult::Done(_, lit) => options_with_defaults(&lit.value, default_options)?,
        IResult::Error => options_with_defaults(input, default_options)?,
    };

    Ok(MacroInput {
        name,
        sample_source,
        options,
    })
}

/// Parses the options block of a `json_typegen` macro invocation. E.g. something like:
/// `{ deny_unknown_fields }`
pub fn options(input: &str) -> Result<Options, String> {
    options_with_defaults(input, Options::default())
}

fn options_with_defaults(input: &str, default_options: Options) -> Result<Options, String> {
    let mut options = default_options;

    let input_after_block = block(input, |remaining, option_name| match option_name.as_ref() {
        "output_mode" => string_option(remaining, "output_mode", |val| {
            options.output_mode = OutputMode::parse(&val).unwrap_or(OutputMode::Rust);
        }),
        "derives" => string_option(remaining, "derives", |val| {
            options.derives = val;
        }),
        "property_name_format" => string_option(remaining, "property_name_format", |val| {
            options.property_name_format = StringTransform::parse(&val)
        }),
        "import_style" => string_option(remaining, "import_style", |val| {
            options.import_style = ImportStyle::parse(&val).unwrap_or(ImportStyle::QualifiedPaths);
        }),
        "field_visibility" => string_option(remaining, "field_visibility", |val| {
            options.field_visibility = Some(val);
        }),
        "deny_unknown_fields" => boolean_option(remaining, "deny_unknown_fields", |val| {
            options.deny_unknown_fields = val;
        }),
        "use_default_for_missing_fields" => {
            boolean_option(remaining, "use_default_for_missing_fields", |val| {
                options.use_default_for_missing_fields = val;
            })
        }
        "allow_option_vec" => boolean_option(remaining, "allow_option_vec", |val| {
            options.allow_option_vec = val;
        }),
        "collect_additional" => boolean_option(remaining, "collect_additional", |val| {
            options.collect_additional = val;
        }),
        "unwrap" => string_option(remaining, "unwrap", |val| {
            options.unwrap = val;
        }),
        key if key.is_empty() || key.starts_with('/') => {
            let (rem, hints) = pointer_block(remaining)?;
            for hint in hints {
                options.hints.push((key.to_string(), hint));
            }
            Ok(rem)
        }
        _ => Err(format!("Unknown option: {}", option_name)),
    })?;

    if !input_after_block.trim().is_empty() {
        fail!("Expected no further tokens after options block", input);
    }

    Ok(options)
}

fn pointer_block(input: &str) -> Result<(&str, Vec<Hint>), String> {
    let mut hints = Vec::new();

    let input = skip_colon(input)?;

    let input_after_block = block(input, |input_after_key, key| match key.as_ref() {
        "use_type" => string_option(input_after_key, "use_type", |val| {
            let hint = match val.as_ref() {
                "map" => Hint::default_map(),
                _ => Hint::opaque_type(val),
            };
            hints.push(hint);
        }),
        "type_name" => string_option(input_after_key, "type_name", |val| {
            hints.push(Hint::type_name(val));
        }),
        _ => Err(format!("Unknown option: {}", key)),
    })?;

    Ok((input_after_block, hints))
}

fn string_option<'a, F: FnMut(String)>(
    input: &'a str,
    name: &'static str,
    mut consumer: F,
) -> Result<&'a str, String> {
    let input = skip_colon(input)?;

    match string(input) {
        IResult::Done(rem, lit) => {
            consumer(lit.value);
            Ok(rem)
        }
        IResult::Error => fail!(
            format!("The argument to '{}' has to be a string literal", name),
            input
        ),
    }
}

fn boolean_option<'a, F: FnMut(bool)>(
    input: &'a str,
    name: &'static str,
    mut consumer: F,
) -> Result<&'a str, String> {
    // interpret { foo, bar } as { foo: true, bar: true }
    if let IResult::Done(_, _) = comma_or_closing_brace(input) {
        consumer(true);
        return Ok(input);
    }

    let input = skip_colon(input)?;

    match boolean(input) {
        IResult::Done(rem, val) => {
            consumer(val);
            Ok(rem)
        }
        IResult::Error => fail!(
            format!("The argument to '{}' has to be a boolean literal", name),
            input
        ),
    }
}

fn block<F>(input: &str, mut field_parser: F) -> Result<&str, String>
where
    F: FnMut(&str, String) -> Result<&str, String>,
{
    let mut input = skip(input, "{", "Expected an opening brace")?;

    loop {
        if let IResult::Done(rem, _) = punct!(input, "}") {
            break Ok(rem);
        }

        let (remaining, key) = match string_or_ident(input) {
            IResult::Done(rem, value) => (rem, value),
            IResult::Error => fail!("Expected an option name", input),
        };

        let remaining = field_parser(remaining, key)?;

        if let IResult::Done(rem, _) = punct!(remaining, "}") {
            break Ok(rem);
        }

        input = skip(remaining, ",", "Expected a comma or a closing brace")?;
    }
}

fn skip_colon(input: &str) -> Result<&str, String> {
    skip(input, ":", "Expected a colon")
}

fn skip<'a>(input: &'a str, symbol: &'static str, msg: &str) -> Result<&'a str, String> {
    match punct!(input, symbol) {
        IResult::Done(rem, _) => Ok(rem),
        IResult::Error => fail!(msg, input),
    }
}

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

    #[test]
    fn barebones_input() {
        assert_eq!(
            macro_input(r#" "Bob", "{}" "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn barebones_input_with_empty_options() {
        assert_eq!(
            macro_input(r#" "Bob", "{}", {} "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn barebones_input_with_options_as_string_literal() {
        assert_eq!(
            macro_input(r#" "Bob", "{}", "{}" "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }
}

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

    #[test]
    fn parses_derives() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn rejects_unknown_options() {
        let result = options(
            r#"{
            "foo_opt": {},
        }"#,
        );

        assert!(
            result.is_err(),
            "Parse result was not Err, but:\n{:?}",
            result
        );
        if let Err(message) = result {
            assert!(
                message.contains("foo_opt"),
                "Error message was:\n'{}'",
                message
            );
        }
    }

    #[test]
    fn parses_empty_pointer_block() {
        let expected = Options::default();

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {},
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_map_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/foo/bar".to_string(), Hint::default_map()));

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {
                    use_type: "map"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_opaque_type_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/foo/bar".to_string(), Hint::opaque_type("FooBar")));

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {
                    use_type: "FooBar"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_type_name_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/baz".to_string(), Hint::type_name("SomeName")));

        assert_eq!(
            options(
                r#"{
                "/baz": {
                    type_name: "SomeName"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_pointer_to_root() {
        let expected = Options::default();

        assert_eq!(
            options(
                r#"{
                "": {},
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_keys_given_as_bare_identifiers() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                derives: "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn trailing_comma_is_optional() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar"
            }"#
            ),
            Ok(expected.clone())
        );

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }
}

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

    #[test]
    fn full_macro_accepts_barebones_macro() {
        assert_eq!(
            full_macro(r#"json_typegen!("Bob", "{}");"#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn full_macro_accepts_barebones_macro_with_options() {
        assert_eq!(
            full_macro(r#"json_typegen!("Bob", "{}", {});"#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }
}
<commit_msg>Fix new warning from trailing comma<commit_after>//! Functions for parsing `json_typegen` macro invocations and their arguments
//!
//! Requires the "option-parsing" feature

use syn;
use syn::parse::{boolean, ident, string};
use synom::{alt, call, named, punct, IResult};

use crate::hints::Hint;
use crate::options::{ImportStyle, Options, OutputMode, StringTransform};

#[derive(PartialEq, Debug)]
pub struct MacroInput {
    pub name: String,
    pub sample_source: String,
    pub options: Options,
}

macro_rules! fail {
    ($base:expr, $input:expr) => {
        return Err(format!(
            "{}, but remaining input was '{}'",
            $base,
            $input.trim()
        ))
    };
}

named!(string_or_ident -> String,
    alt!(
        ident => { |ident: syn::Ident| ident.to_string() }
        |
        string => { |lit: syn::StrLit| lit.value }
    )
);

named!(comma_or_closing_brace -> &str,
    alt!(punct!(",") | punct!("}"))
);

/// Parses a full `json_typegen` macro invocation. E.g. something like
/// `json_typegen!("Foo", "http://example.com/sample.json", { deny_unknown_fields });`
pub fn full_macro(input: &str) -> Result<MacroInput, String> {
    let input = input.trim();

    let prefix = "json_typegen!(";
    if !input.starts_with(prefix) {
        fail!("Unable to parse macro. Expected 'json_typegen!('", input)
    }

    let suffix = ");";
    if !input.ends_with(suffix) {
        fail!("Unable to parse macro. Expected it to end with ');'", input)
    }

    let input = &input[prefix.len()..input.len() - suffix.len()].trim();

    macro_input(input)
}

/// Parses the arguments to a `json_typegen` macro invocation. E.g. something like
/// `"Foo", "http://example.com/sample.json", { deny_unknown_fields }`
pub fn macro_input(input: &str) -> Result<MacroInput, String> {
    let (input, name) = match string(input) {
        IResult::Done(input, lit) => (input, lit.value),
        IResult::Error => fail!("First argument must be a string literal", input),
    };

    let input = skip(input, ",", "Expected a comma after first argument")?;

    let (input, sample_source) = match string(input) {
        IResult::Done(input, lit) => (input, lit.value),
        IResult::Error => fail!("Second argument must be a string literal", input),
    };

    let default_options = Options::macro_default();

    if input.trim().is_empty() {
        return Ok(MacroInput {
            name,
            sample_source,
            options: default_options,
        });
    }

    let input = skip(
        input,
        ",",
        "Expected a comma or end of input after second argument",
    )?;

    let options = match string(input) {
        IResult::Done(_, lit) => options_with_defaults(&lit.value, default_options)?,
        IResult::Error => options_with_defaults(input, default_options)?,
    };

    Ok(MacroInput {
        name,
        sample_source,
        options,
    })
}

/// Parses the options block of a `json_typegen` macro invocation. E.g. something like:
/// `{ deny_unknown_fields }`
pub fn options(input: &str) -> Result<Options, String> {
    options_with_defaults(input, Options::default())
}

fn options_with_defaults(input: &str, default_options: Options) -> Result<Options, String> {
    let mut options = default_options;

    let input_after_block = block(input, |remaining, option_name| match option_name.as_ref() {
        "output_mode" => string_option(remaining, "output_mode", |val| {
            options.output_mode = OutputMode::parse(&val).unwrap_or(OutputMode::Rust);
        }),
        "derives" => string_option(remaining, "derives", |val| {
            options.derives = val;
        }),
        "property_name_format" => string_option(remaining, "property_name_format", |val| {
            options.property_name_format = StringTransform::parse(&val)
        }),
        "import_style" => string_option(remaining, "import_style", |val| {
            options.import_style = ImportStyle::parse(&val).unwrap_or(ImportStyle::QualifiedPaths);
        }),
        "field_visibility" => string_option(remaining, "field_visibility", |val| {
            options.field_visibility = Some(val);
        }),
        "deny_unknown_fields" => boolean_option(remaining, "deny_unknown_fields", |val| {
            options.deny_unknown_fields = val;
        }),
        "use_default_for_missing_fields" => {
            boolean_option(remaining, "use_default_for_missing_fields", |val| {
                options.use_default_for_missing_fields = val;
            })
        }
        "allow_option_vec" => boolean_option(remaining, "allow_option_vec", |val| {
            options.allow_option_vec = val;
        }),
        "collect_additional" => boolean_option(remaining, "collect_additional", |val| {
            options.collect_additional = val;
        }),
        "unwrap" => string_option(remaining, "unwrap", |val| {
            options.unwrap = val;
        }),
        key if key.is_empty() || key.starts_with('/') => {
            let (rem, hints) = pointer_block(remaining)?;
            for hint in hints {
                options.hints.push((key.to_string(), hint));
            }
            Ok(rem)
        }
        _ => Err(format!("Unknown option: {}", option_name)),
    })?;

    if !input_after_block.trim().is_empty() {
        fail!("Expected no further tokens after options block", input);
    }

    Ok(options)
}

fn pointer_block(input: &str) -> Result<(&str, Vec<Hint>), String> {
    let mut hints = Vec::new();

    let input = skip_colon(input)?;

    let input_after_block = block(input, |input_after_key, key| match key.as_ref() {
        "use_type" => string_option(input_after_key, "use_type", |val| {
            let hint = match val.as_ref() {
                "map" => Hint::default_map(),
                _ => Hint::opaque_type(val),
            };
            hints.push(hint);
        }),
        "type_name" => string_option(input_after_key, "type_name", |val| {
            hints.push(Hint::type_name(val));
        }),
        _ => Err(format!("Unknown option: {}", key)),
    })?;

    Ok((input_after_block, hints))
}

fn string_option<'a, F: FnMut(String)>(
    input: &'a str,
    name: &'static str,
    mut consumer: F,
) -> Result<&'a str, String> {
    let input = skip_colon(input)?;

    match string(input) {
        IResult::Done(rem, lit) => {
            consumer(lit.value);
            Ok(rem)
        }
        IResult::Error => fail!(
            format!("The argument to '{}' has to be a string literal", name),
            input
        ),
    }
}

fn boolean_option<'a, F: FnMut(bool)>(
    input: &'a str,
    name: &'static str,
    mut consumer: F,
) -> Result<&'a str, String> {
    // interpret { foo, bar } as { foo: true, bar: true }
    if let IResult::Done(_, _) = comma_or_closing_brace(input) {
        consumer(true);
        return Ok(input);
    }

    let input = skip_colon(input)?;

    match boolean(input) {
        IResult::Done(rem, val) => {
            consumer(val);
            Ok(rem)
        }
        IResult::Error => fail!(
            format!("The argument to '{}' has to be a boolean literal", name),
            input
        ),
    }
}

fn block<F>(input: &str, mut field_parser: F) -> Result<&str, String>
where
    F: FnMut(&str, String) -> Result<&str, String>,
{
    let mut input = skip(input, "{", "Expected an opening brace")?;

    loop {
        if let IResult::Done(rem, _) = punct!(input, "}") {
            break Ok(rem);
        }

        let (remaining, key) = match string_or_ident(input) {
            IResult::Done(rem, value) => (rem, value),
            IResult::Error => fail!("Expected an option name", input),
        };

        let remaining = field_parser(remaining, key)?;

        if let IResult::Done(rem, _) = punct!(remaining, "}") {
            break Ok(rem);
        }

        input = skip(remaining, ",", "Expected a comma or a closing brace")?;
    }
}

fn skip_colon(input: &str) -> Result<&str, String> {
    skip(input, ":", "Expected a colon")
}

fn skip<'a>(input: &'a str, symbol: &'static str, msg: &str) -> Result<&'a str, String> {
    match punct!(input, symbol) {
        IResult::Done(rem, _) => Ok(rem),
        IResult::Error => fail!(msg, input),
    }
}

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

    #[test]
    fn barebones_input() {
        assert_eq!(
            macro_input(r#" "Bob", "{}" "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn barebones_input_with_empty_options() {
        assert_eq!(
            macro_input(r#" "Bob", "{}", {} "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn barebones_input_with_options_as_string_literal() {
        assert_eq!(
            macro_input(r#" "Bob", "{}", "{}" "#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }
}

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

    #[test]
    fn parses_derives() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn rejects_unknown_options() {
        let result = options(
            r#"{
            "foo_opt": {},
        }"#,
        );

        assert!(
            result.is_err(),
            "Parse result was not Err, but:\n{:?}",
            result
        );
        if let Err(message) = result {
            assert!(
                message.contains("foo_opt"),
                "Error message was:\n'{}'",
                message
            );
        }
    }

    #[test]
    fn parses_empty_pointer_block() {
        let expected = Options::default();

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {},
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_map_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/foo/bar".to_string(), Hint::default_map()));

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {
                    use_type: "map"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_opaque_type_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/foo/bar".to_string(), Hint::opaque_type("FooBar")));

        assert_eq!(
            options(
                r#"{
                "/foo/bar": {
                    use_type: "FooBar"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_type_name_hint() {
        let mut expected = Options::default();
        expected
            .hints
            .push(("/baz".to_string(), Hint::type_name("SomeName")));

        assert_eq!(
            options(
                r#"{
                "/baz": {
                    type_name: "SomeName"
                },
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_pointer_to_root() {
        let expected = Options::default();

        assert_eq!(
            options(
                r#"{
                "": {},
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn parses_keys_given_as_bare_identifiers() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                derives: "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }

    #[test]
    fn trailing_comma_is_optional() {
        let expected = Options {
            derives: "Foo, Bar".into(),
            ..Options::default()
        };

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar"
            }"#
            ),
            Ok(expected.clone())
        );

        assert_eq!(
            options(
                r#"{
                "derives": "Foo, Bar",
            }"#
            ),
            Ok(expected)
        );
    }
}

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

    #[test]
    fn full_macro_accepts_barebones_macro() {
        assert_eq!(
            full_macro(r#"json_typegen!("Bob", "{}");"#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }

    #[test]
    fn full_macro_accepts_barebones_macro_with_options() {
        assert_eq!(
            full_macro(r#"json_typegen!("Bob", "{}", {});"#),
            Ok(MacroInput {
                name: "Bob".to_string(),
                sample_source: "{}".to_string(),
                options: Options::macro_default(),
            })
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::f64;
use std::iter;
use std::slice;

use num::traits::{cast, NumCast};
use itertools::Itertools;

use bio::stats::logprobs::{self, LogProb};

/// Implementation of a cumulative distribution function.
#[derive(Debug, Clone)]
pub struct CDF<T: PartialOrd> {
    inner: Vec<(T, LogProb)>
}

impl<T: PartialOrd> CDF<T> {
    /// Create CDF from given probability mass function (PMF). The PMF may contain duplicate values
    /// the probabilities of which are summed during generation of the CDF.
    pub fn from_pmf(mut entries: Vec<(T, LogProb)>) -> Self {
        entries.sort_by(|&(ref a, _), &(ref b, _)| a.partial_cmp(b).unwrap());
        let mut inner: Vec<(T, LogProb)> = Vec::new();
        for mut e in entries.into_iter() {
            let p = logprobs::add(inner.last().map_or(f64::NEG_INFINITY, |e| e.1), e.1);
            if !inner.is_empty() && inner.last().unwrap().0 == e.0 {
                inner.last_mut().unwrap().1 = p;
            }
            else {
                e.1 = p;
                inner.push(e);
            }
        }
        let mut cdf = CDF {
            inner: inner
        };

        if relative_eq!(cdf.total_prob(), 0.0) && cdf.total_prob() > 0.0 {
            cdf.inner.last_mut().unwrap().1 = 0.0;
        }

        cdf
    }

    /// Create CDF from iterator. This can be used to replace the values of a CDF.
    pub fn from_cdf<I: Iterator<Item = (T, LogProb)>>(entries: I) -> Self {
        CDF { inner: entries.collect_vec() }
    }

    pub fn reduce(self) -> Self {
        let mut inner = Vec::new();
        let mut last = f64::NEG_INFINITY;
        for e in self.inner.into_iter() {
            if last != e.1 {
                last = e.1;
                inner.push(e);
            }
        }
        CDF { inner: inner }
    }

    pub fn sample(mut self, n: usize) -> Self {
        if self.inner.len() <= n {
            self
        }
        else {
            let s = self.inner.len() / (n - 1);
            let last = self.inner.pop().unwrap();
            let mut inner = self.inner.into_iter().step(s).collect_vec();
            inner.push(last);
            CDF {
                inner: inner
            }
        }
    }

    pub fn iter(&self) -> slice::Iter<(T, f64)>{
        self.inner.iter()
    }

    pub fn iter_pmf<'a>(&'a self) -> CDFPMFIter<'a, T> {
        fn cdf_to_pmf<'a, G>(last_prob: &mut LogProb, e: &'a (G, LogProb)) -> Option<(&'a G, LogProb)> {
            let &(ref value, cdf_prob) = e;
            let prob = logprobs::sub(cdf_prob, *last_prob);
            *last_prob = cdf_prob;
            Some((value, prob))
        }
        self.inner.iter().scan(f64::NEG_INFINITY, cdf_to_pmf)
    }

    /// Get cumulative probability for a given value. If the value is not present,
    /// return the probability of the previous value.
    pub fn get(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => self.inner[i].1,
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn get_pmf(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => if i > 0 { logprobs::sub(self.inner[i].1, self.inner[i - 1].1) } else { self.inner[0].1 },
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn total_prob(&self) -> LogProb {
        let &(_, prob) = self.inner.last().unwrap();
        prob
    }

    /// Return maximum a posteriori probability estimate (MAP).
    pub fn map(&self) -> &T {
        let mut max = self.iter_pmf().next().unwrap();
        for e in self.iter_pmf() {
            if e.1 >= max.1 {
                max = e;
            }
        }
        &max.0
    }

    /// Return the 95% credible interval.
    pub fn credible_interval(&self) -> (&T, &T) {
        let lower = self.inner.binary_search_by(|&(_, p)| p.partial_cmp(&0.025f64.ln()).unwrap()).unwrap_or_else(|i| if i > 0 { i - 1 } else { 0 });
        let lower_p = self.inner[lower].1;
        let mut upper = self.inner[lower + 1..].binary_search_by(|&(_, p)| logprobs::sub(p, lower_p).partial_cmp(&0.95f64.ln()).unwrap()).unwrap_or_else(|i| i);
        if upper == self.inner.len() {
            upper -= 1;
        }

        (&self.inner[lower].0, &self.inner[upper].0)
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }
}

impl<T: NumCast + Clone + PartialOrd> CDF<T> {
    pub fn expected_value(&self) -> f64 {
        self.iter_pmf().map(|(value, prob)| {
            cast::<T, f64>(value.clone()).unwrap() * prob.exp()
        }).fold(0.0f64, |s, e| s + e)
    }

    pub fn variance(&self) -> f64 {
        let ev = self.expected_value();
        self.iter_pmf().map(|(value, prob)| {
                (cast::<T, f64>(value.clone()).unwrap() - ev).powi(2) * prob.exp()
        }).fold(0.0, |s, e| s + e)
    }

    pub fn standard_deviation(&self) -> f64 {
        self.variance().sqrt()
    }
}

pub type CDFPMFIter<'a, T> = iter::Scan<slice::Iter<'a, (T, LogProb)>, LogProb, fn(&mut LogProb, &'a (T, LogProb)) -> Option<(&'a T, LogProb)>>;

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

    #[test]
    fn test_cdf() {
        let mut pmf = vec![(0.0, 0.1f64.ln())];
        for i in 0..9 {
            pmf.push((i as f64, 0.1f64.ln()));
        }
        println!("{:?}", pmf);

        let cdf = CDF::from_pmf(pmf.clone());
        println!("{:?}", cdf);
        for &(value, prob) in pmf.iter().skip(2) {
            assert_ulps_eq!(prob, cdf.get_pmf(&value).unwrap(), epsilon = 0.0000000000001);
        }
        assert_relative_eq!(cdf.total_prob(), 1.0f64.ln());
        assert_relative_eq!(cdf.get(&1.0).unwrap(), 0.3f64.ln(), epsilon = 0.00000001);
    }
}
<commit_msg>Fix upper index.<commit_after>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::f64;
use std::iter;
use std::slice;

use num::traits::{cast, NumCast};
use itertools::Itertools;

use bio::stats::logprobs::{self, LogProb};

/// Implementation of a cumulative distribution function.
#[derive(Debug, Clone)]
pub struct CDF<T: PartialOrd> {
    inner: Vec<(T, LogProb)>
}

impl<T: PartialOrd> CDF<T> {
    /// Create CDF from given probability mass function (PMF). The PMF may contain duplicate values
    /// the probabilities of which are summed during generation of the CDF.
    pub fn from_pmf(mut entries: Vec<(T, LogProb)>) -> Self {
        entries.sort_by(|&(ref a, _), &(ref b, _)| a.partial_cmp(b).unwrap());
        let mut inner: Vec<(T, LogProb)> = Vec::new();
        for mut e in entries.into_iter() {
            let p = logprobs::add(inner.last().map_or(f64::NEG_INFINITY, |e| e.1), e.1);
            if !inner.is_empty() && inner.last().unwrap().0 == e.0 {
                inner.last_mut().unwrap().1 = p;
            }
            else {
                e.1 = p;
                inner.push(e);
            }
        }
        let mut cdf = CDF {
            inner: inner
        };

        if relative_eq!(cdf.total_prob(), 0.0) && cdf.total_prob() > 0.0 {
            cdf.inner.last_mut().unwrap().1 = 0.0;
        }

        cdf
    }

    /// Create CDF from iterator. This can be used to replace the values of a CDF.
    pub fn from_cdf<I: Iterator<Item = (T, LogProb)>>(entries: I) -> Self {
        CDF { inner: entries.collect_vec() }
    }

    pub fn reduce(self) -> Self {
        let mut inner = Vec::new();
        let mut last = f64::NEG_INFINITY;
        for e in self.inner.into_iter() {
            if last != e.1 {
                last = e.1;
                inner.push(e);
            }
        }
        CDF { inner: inner }
    }

    pub fn sample(mut self, n: usize) -> Self {
        if self.inner.len() <= n {
            self
        }
        else {
            let s = self.inner.len() / (n - 1);
            let last = self.inner.pop().unwrap();
            let mut inner = self.inner.into_iter().step(s).collect_vec();
            inner.push(last);
            CDF {
                inner: inner
            }
        }
    }

    pub fn iter(&self) -> slice::Iter<(T, f64)>{
        self.inner.iter()
    }

    pub fn iter_pmf<'a>(&'a self) -> CDFPMFIter<'a, T> {
        fn cdf_to_pmf<'a, G>(last_prob: &mut LogProb, e: &'a (G, LogProb)) -> Option<(&'a G, LogProb)> {
            let &(ref value, cdf_prob) = e;
            let prob = logprobs::sub(cdf_prob, *last_prob);
            *last_prob = cdf_prob;
            Some((value, prob))
        }
        self.inner.iter().scan(f64::NEG_INFINITY, cdf_to_pmf)
    }

    /// Get cumulative probability for a given value. If the value is not present,
    /// return the probability of the previous value.
    pub fn get(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => self.inner[i].1,
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn get_pmf(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => if i > 0 { logprobs::sub(self.inner[i].1, self.inner[i - 1].1) } else { self.inner[0].1 },
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn total_prob(&self) -> LogProb {
        let &(_, prob) = self.inner.last().unwrap();
        prob
    }

    /// Return maximum a posteriori probability estimate (MAP).
    pub fn map(&self) -> &T {
        let mut max = self.iter_pmf().next().unwrap();
        for e in self.iter_pmf() {
            if e.1 >= max.1 {
                max = e;
            }
        }
        &max.0
    }

    /// Return the 95% credible interval.
    pub fn credible_interval(&self) -> (&T, &T) {
        let lower = self.inner.binary_search_by(|&(_, p)| p.partial_cmp(&0.025f64.ln()).unwrap()).unwrap_or_else(|i| if i > 0 { i - 1 } else { 0 });
        let lower_p = self.inner[lower].1;
        let mut upper = lower + self.inner[lower..].binary_search_by(|&(_, p)| logprobs::sub(p, lower_p).partial_cmp(&0.95f64.ln()).unwrap()).unwrap_or_else(|i| i);
        if upper == self.inner.len() {
            upper -= 1;
        }

        (&self.inner[lower].0, &self.inner[upper].0)
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }
}

impl<T: NumCast + Clone + PartialOrd> CDF<T> {
    pub fn expected_value(&self) -> f64 {
        self.iter_pmf().map(|(value, prob)| {
            cast::<T, f64>(value.clone()).unwrap() * prob.exp()
        }).fold(0.0f64, |s, e| s + e)
    }

    pub fn variance(&self) -> f64 {
        let ev = self.expected_value();
        self.iter_pmf().map(|(value, prob)| {
                (cast::<T, f64>(value.clone()).unwrap() - ev).powi(2) * prob.exp()
        }).fold(0.0, |s, e| s + e)
    }

    pub fn standard_deviation(&self) -> f64 {
        self.variance().sqrt()
    }
}

pub type CDFPMFIter<'a, T> = iter::Scan<slice::Iter<'a, (T, LogProb)>, LogProb, fn(&mut LogProb, &'a (T, LogProb)) -> Option<(&'a T, LogProb)>>;

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

    #[test]
    fn test_cdf() {
        let mut pmf = vec![(0.0, 0.1f64.ln())];
        for i in 0..9 {
            pmf.push((i as f64, 0.1f64.ln()));
        }
        println!("{:?}", pmf);

        let cdf = CDF::from_pmf(pmf.clone());
        println!("{:?}", cdf);
        for &(value, prob) in pmf.iter().skip(2) {
            assert_ulps_eq!(prob, cdf.get_pmf(&value).unwrap(), epsilon = 0.0000000000001);
        }
        assert_relative_eq!(cdf.total_prob(), 1.0f64.ln());
        assert_relative_eq!(cdf.get(&1.0).unwrap(), 0.3f64.ln(), epsilon = 0.00000001);
    }
}
<|endoftext|>


<commit_before>#![allow(missing_docs)]

pub type AST = Vec<Definition>;
pub type Identifier = String;

// The following structures are used to help simplify building the AST in the grammar. Ideally
// these would not be exposed outside the crate, but the compiler seems to think they are exposed
// as private types when `pub(super)` is used. This is not the case since all of their variants are
// matched into other structures, but I suppose it is not a big deal.

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub(super) enum BufferRelatedType {
    ArrayBuffer,
    DataView,
    Float32Array,
    Float64Array,
    Int16Array,
    Int32Array,
    Int8Array,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PrimitiveType {
    Boolean,
    Byte,
    Octet,
    UnrestrictedFloat(UnrestrictedFloatType),
    UnsignedInteger(UnsignedIntegerType),
}

/// Do not use - for grammar use only.
#[derive(Clone, Debug, PartialEq)]
pub enum Stringifier {
    Attribute(Attribute),
    Operation(Operation),
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UnrestrictedFloatType {
    RestrictedDouble,
    RestrictedFloat,
    UnrestrictedDouble,
    UnrestrictedFloat,
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UnsignedIntegerType {
    SignedLong,
    SignedLongLong,
    SignedShort,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

// Publically available AST structures

#[derive(Clone, Debug, PartialEq)]
pub struct Argument {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub default: Option<DefaultValue>,
    pub name: Identifier,
    pub optional: bool,
    pub type_: Box<Type>,
    pub variadic: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ArgumentListExtendedAttribute {
    pub arguments: Vec<Argument>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Attribute {
    Regular(RegularAttribute),
    Static(StaticAttribute),
    Stringifier(StringifierAttribute),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Callback {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub struct CallbackInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Const {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub nullable: bool,
    pub type_: ConstType,
    pub value: ConstValue,
}

#[allow(variant_size_differences)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum ConstType {
    Boolean,
    Byte,
    Identifier(Identifier),
    Octet,
    RestrictedDouble,
    RestrictedFloat,
    SignedLong,
    SignedLongLong,
    SignedShort,
    UnrestrictedDouble,
    UnrestrictedFloat,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConstValue {
    BooleanLiteral(bool),
    FloatLiteral(f64),
    IntegerLiteral(i64),
    Null,
}

#[derive(Clone, Debug, PartialEq)]
pub enum DefaultValue {
    ConstValue(ConstValue),
    EmptySequence,
    StringLiteral(String),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Definition {
    Callback(Callback),
    Dictionary(Dictionary),
    Enum(Enum),
    Includes(Includes),
    Interface(Interface),
    Mixin(Mixin),
    Namespace(Namespace),
    Typedef(Typedef),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Dictionary {
    NonPartial(NonPartialDictionary),
    Partial(PartialDictionary),
}

#[derive(Clone, Debug, PartialEq)]
pub struct DictionaryMember {
    pub default: Option<DefaultValue>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub required: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Enum {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: String,
    pub variants: Vec<String>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ExplicitStringifierOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ExtendedAttribute {
    ArgumentList(ArgumentListExtendedAttribute),
    Identifier(IdentifierExtendedAttribute),
    IdentifierList(IdentifierListExtendedAttribute),
    NamedArgumentList(NamedArgumentListExtendedAttribute),
    NoArguments(Other),
    // Other(OtherExtendedAttribute),
}

#[derive(Clone, Debug, PartialEq)]
pub struct IdentifierExtendedAttribute {
    pub lhs: Identifier,
    pub rhs: Other,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct IdentifierListExtendedAttribute {
    pub lhs: Identifier,
    pub rhs: Vec<Identifier>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ImplicitStringifierOperation {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Includes {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub includee: Identifier,
    pub includer: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Interface {
    Callback(CallbackInterface),
    NonPartial(NonPartialInterface),
    Partial(PartialInterface),
}

#[derive(Clone, Debug, PartialEq)]
pub enum InterfaceMember {
    Attribute(Attribute),
    Const(Const),
    Iterable(Iterable),
    Maplike(Maplike),
    Operation(Operation),
    Setlike(Setlike),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Iterable {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub key_type: Option<Box<Type>>,
    pub value_type: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Maplike {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub key_type: Box<Type>,
    pub read_only: bool,
    pub value_type: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Mixin {
    NonPartial(NonPartialMixin),
    Partial(PartialMixin),
}

#[derive(Clone, Debug, PartialEq)]
pub enum MixinMember {
    Attribute(Attribute),
    Const(Const),
    Operation(Operation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct NamedArgumentListExtendedAttribute {
    pub lhs_name: Identifier,
    pub rhs_arguments: Vec<Argument>,
    pub rhs_name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Namespace {
    NonPartial(NonPartialNamespace),
    Partial(PartialNamespace),
}

#[derive(Clone, Debug, PartialEq)]
pub enum NamespaceMember {
    Attribute(Attribute),
    Operation(Operation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialDictionary {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<DictionaryMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialMixin {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<MixinMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialNamespace {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<NamespaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Operation {
    Regular(RegularOperation),
    Special(SpecialOperation),
    Static(StaticOperation),
    Stringifier(StringifierOperation),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Other {
    Any,
    ArrayBuffer,
    Attribute,
    Boolean,
    Byte,
    ByteString,
    Callback,
    Const,
    DOMString,
    DataView,
    Deleter,
    Dictionary,
    Double,
    Enum,
    False,
    Float,
    Float32Array,
    Float64Array,
    FrozenArray,
    Getter,
    Includes,
    Inherit,
    Int16Array,
    Int32Array,
    Int8Array,
    Interface,
    Iterable,
    Long,
    Maplike,
    Namespace,
    NegativeInfinity,
    NaN,
    Null,
    Object,
    Octet,
    Optional,
    Or,
    Partial,
    PositiveInfinity,
    Required,
    Sequence,
    Setlike,
    Setter,
    Short,
    Static,
    Stringifier,
    True,
    Typedef,
    USVString,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
    Unrestricted,
    Unsigned,
    Void,

    FloatLiteral(f64),
    Identifier(Identifier),
    IntegerLiteral(i64),
    OtherLiteral(char),
    StringLiteral(String),

    Colon,
    Ellipsis,
    Equals,
    GreaterThan,
    Hyphen,
    LessThan,
    Period,
    QuestionMark,
    Semicolon,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OtherExtendedAttribute {
    Nested {
        group_type: OtherExtendedAttributeGroupType,
        inner: Option<Box<ExtendedAttribute>>,
        rest: Option<Box<ExtendedAttribute>>,
    },
    Other {
        other: Option<Other>,
        rest: Option<Box<ExtendedAttribute>>,
    },
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum OtherExtendedAttributeGroupType {
    Brace,
    Bracket,
    Parenthesis,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialDictionary {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<DictionaryMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialMixin {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<MixinMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialNamespace {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<NamespaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct RegularAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: bool,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct RegularOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ReturnType {
    NonVoid(Box<Type>),
    Void,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Setlike {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Special {
    Deleter,
    Getter,
    Setter,
}

#[derive(Clone, Debug, PartialEq)]
pub struct SpecialOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
    pub special_keywords: Vec<Special>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StaticAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StaticOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum StringType {
    ByteString,
    DOMString,
    USVString,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StringifierAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[allow(variant_size_differences)]
#[derive(Clone, Debug, PartialEq)]
pub enum StringifierOperation {
    Explicit(ExplicitStringifierOperation),
    Implicit(ImplicitStringifierOperation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Type {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub kind: TypeKind,
    pub nullable: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub enum TypeKind {
    Any,
    ArrayBuffer,
    Boolean,
    Byte,
    ByteString,
    DOMString,
    DataView,
    Error,
    Float32Array,
    Float64Array,
    FrozenArray(Box<Type>),
    Identifier(Identifier),
    Int16Array,
    Int32Array,
    Int8Array,
    Octet,
    Object,
    Promise(ReturnType),
    Record(StringType, Box<Type>),
    RestrictedDouble,
    RestrictedFloat,
    Sequence(Box<Type>),
    SignedLong,
    SignedLongLong,
    SignedShort,
    Symbol,
    USVString,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
    Union(Vec<Box<Type>>),
    UnrestrictedDouble,
    UnrestrictedFloat,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Typedef {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub type_: Box<Type>,
}

/// Consumes a vector of ASTs that are flattened into a single AST. This is helpful if you want to
/// merge ASTs from multiple files and be able to use the visitor pattern across all of them.
pub fn flatten_asts(asts: Vec<AST>) -> AST {
    asts.into_iter().flat_map(|ast| ast).collect()
}

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

    #[test]
    fn test_flatten_asts() {
        let ast1 = vec![
            Definition::Interface(Interface::NonPartial(NonPartialInterface {
                extended_attributes: vec![],
                inherits: None,
                members: vec![],
                name: "Node".to_string(),
            })),
        ];
        let ast2 = vec![
            Definition::Typedef(Typedef {
                extended_attributes: vec![],
                name: "Typedef".to_string(),
                type_: Box::new(Type {
                    extended_attributes: vec![],
                    kind: TypeKind::Any,
                    nullable: false,
                }),
            }),
        ];

        assert_eq!(
            flatten_asts(vec![ast1.clone(), ast2.clone()]),
            vec![ast1[0].clone(), ast2[0].clone()]
        );
    }
}
<commit_msg>revert scope change<commit_after>#![allow(missing_docs)]

pub type AST = Vec<Definition>;
pub type Identifier = String;

// The following structures are used to help simplify building the AST in the grammar. Ideally
// these would not be exposed outside the crate, but the compiler seems to think they are exposed
// as private types when `pub(super)` is used. This is not the case since all of their variants are
// matched into other structures, but I suppose it is not a big deal.

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum BufferRelatedType {
    ArrayBuffer,
    DataView,
    Float32Array,
    Float64Array,
    Int16Array,
    Int32Array,
    Int8Array,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PrimitiveType {
    Boolean,
    Byte,
    Octet,
    UnrestrictedFloat(UnrestrictedFloatType),
    UnsignedInteger(UnsignedIntegerType),
}

/// Do not use - for grammar use only.
#[derive(Clone, Debug, PartialEq)]
pub enum Stringifier {
    Attribute(Attribute),
    Operation(Operation),
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UnrestrictedFloatType {
    RestrictedDouble,
    RestrictedFloat,
    UnrestrictedDouble,
    UnrestrictedFloat,
}

/// Do not use - for grammar use only.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UnsignedIntegerType {
    SignedLong,
    SignedLongLong,
    SignedShort,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

// Publically available AST structures

#[derive(Clone, Debug, PartialEq)]
pub struct Argument {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub default: Option<DefaultValue>,
    pub name: Identifier,
    pub optional: bool,
    pub type_: Box<Type>,
    pub variadic: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ArgumentListExtendedAttribute {
    pub arguments: Vec<Argument>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Attribute {
    Regular(RegularAttribute),
    Static(StaticAttribute),
    Stringifier(StringifierAttribute),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Callback {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub struct CallbackInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Const {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub nullable: bool,
    pub type_: ConstType,
    pub value: ConstValue,
}

#[allow(variant_size_differences)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum ConstType {
    Boolean,
    Byte,
    Identifier(Identifier),
    Octet,
    RestrictedDouble,
    RestrictedFloat,
    SignedLong,
    SignedLongLong,
    SignedShort,
    UnrestrictedDouble,
    UnrestrictedFloat,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConstValue {
    BooleanLiteral(bool),
    FloatLiteral(f64),
    IntegerLiteral(i64),
    Null,
}

#[derive(Clone, Debug, PartialEq)]
pub enum DefaultValue {
    ConstValue(ConstValue),
    EmptySequence,
    StringLiteral(String),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Definition {
    Callback(Callback),
    Dictionary(Dictionary),
    Enum(Enum),
    Includes(Includes),
    Interface(Interface),
    Mixin(Mixin),
    Namespace(Namespace),
    Typedef(Typedef),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Dictionary {
    NonPartial(NonPartialDictionary),
    Partial(PartialDictionary),
}

#[derive(Clone, Debug, PartialEq)]
pub struct DictionaryMember {
    pub default: Option<DefaultValue>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub required: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Enum {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: String,
    pub variants: Vec<String>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ExplicitStringifierOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ExtendedAttribute {
    ArgumentList(ArgumentListExtendedAttribute),
    Identifier(IdentifierExtendedAttribute),
    IdentifierList(IdentifierListExtendedAttribute),
    NamedArgumentList(NamedArgumentListExtendedAttribute),
    NoArguments(Other),
    // Other(OtherExtendedAttribute),
}

#[derive(Clone, Debug, PartialEq)]
pub struct IdentifierExtendedAttribute {
    pub lhs: Identifier,
    pub rhs: Other,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct IdentifierListExtendedAttribute {
    pub lhs: Identifier,
    pub rhs: Vec<Identifier>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ImplicitStringifierOperation {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Includes {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub includee: Identifier,
    pub includer: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Interface {
    Callback(CallbackInterface),
    NonPartial(NonPartialInterface),
    Partial(PartialInterface),
}

#[derive(Clone, Debug, PartialEq)]
pub enum InterfaceMember {
    Attribute(Attribute),
    Const(Const),
    Iterable(Iterable),
    Maplike(Maplike),
    Operation(Operation),
    Setlike(Setlike),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Iterable {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub key_type: Option<Box<Type>>,
    pub value_type: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Maplike {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub key_type: Box<Type>,
    pub read_only: bool,
    pub value_type: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Mixin {
    NonPartial(NonPartialMixin),
    Partial(PartialMixin),
}

#[derive(Clone, Debug, PartialEq)]
pub enum MixinMember {
    Attribute(Attribute),
    Const(Const),
    Operation(Operation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct NamedArgumentListExtendedAttribute {
    pub lhs_name: Identifier,
    pub rhs_arguments: Vec<Argument>,
    pub rhs_name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Namespace {
    NonPartial(NonPartialNamespace),
    Partial(PartialNamespace),
}

#[derive(Clone, Debug, PartialEq)]
pub enum NamespaceMember {
    Attribute(Attribute),
    Operation(Operation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialDictionary {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<DictionaryMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: Option<Identifier>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialMixin {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<MixinMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct NonPartialNamespace {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<NamespaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Operation {
    Regular(RegularOperation),
    Special(SpecialOperation),
    Static(StaticOperation),
    Stringifier(StringifierOperation),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Other {
    Any,
    ArrayBuffer,
    Attribute,
    Boolean,
    Byte,
    ByteString,
    Callback,
    Const,
    DOMString,
    DataView,
    Deleter,
    Dictionary,
    Double,
    Enum,
    False,
    Float,
    Float32Array,
    Float64Array,
    FrozenArray,
    Getter,
    Includes,
    Inherit,
    Int16Array,
    Int32Array,
    Int8Array,
    Interface,
    Iterable,
    Long,
    Maplike,
    Namespace,
    NegativeInfinity,
    NaN,
    Null,
    Object,
    Octet,
    Optional,
    Or,
    Partial,
    PositiveInfinity,
    Required,
    Sequence,
    Setlike,
    Setter,
    Short,
    Static,
    Stringifier,
    True,
    Typedef,
    USVString,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
    Unrestricted,
    Unsigned,
    Void,

    FloatLiteral(f64),
    Identifier(Identifier),
    IntegerLiteral(i64),
    OtherLiteral(char),
    StringLiteral(String),

    Colon,
    Ellipsis,
    Equals,
    GreaterThan,
    Hyphen,
    LessThan,
    Period,
    QuestionMark,
    Semicolon,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OtherExtendedAttribute {
    Nested {
        group_type: OtherExtendedAttributeGroupType,
        inner: Option<Box<ExtendedAttribute>>,
        rest: Option<Box<ExtendedAttribute>>,
    },
    Other {
        other: Option<Other>,
        rest: Option<Box<ExtendedAttribute>>,
    },
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum OtherExtendedAttributeGroupType {
    Brace,
    Bracket,
    Parenthesis,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialDictionary {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<DictionaryMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialInterface {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<InterfaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialMixin {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<MixinMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PartialNamespace {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub members: Vec<NamespaceMember>,
    pub name: Identifier,
}

#[derive(Clone, Debug, PartialEq)]
pub struct RegularAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub inherits: bool,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct RegularOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ReturnType {
    NonVoid(Box<Type>),
    Void,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Setlike {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Special {
    Deleter,
    Getter,
    Setter,
}

#[derive(Clone, Debug, PartialEq)]
pub struct SpecialOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
    pub special_keywords: Vec<Special>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StaticAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StaticOperation {
    pub arguments: Vec<Argument>,
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Option<Identifier>,
    pub return_type: ReturnType,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum StringType {
    ByteString,
    DOMString,
    USVString,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StringifierAttribute {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub read_only: bool,
    pub type_: Box<Type>,
}

#[allow(variant_size_differences)]
#[derive(Clone, Debug, PartialEq)]
pub enum StringifierOperation {
    Explicit(ExplicitStringifierOperation),
    Implicit(ImplicitStringifierOperation),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Type {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub kind: TypeKind,
    pub nullable: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub enum TypeKind {
    Any,
    ArrayBuffer,
    Boolean,
    Byte,
    ByteString,
    DOMString,
    DataView,
    Error,
    Float32Array,
    Float64Array,
    FrozenArray(Box<Type>),
    Identifier(Identifier),
    Int16Array,
    Int32Array,
    Int8Array,
    Octet,
    Object,
    Promise(ReturnType),
    Record(StringType, Box<Type>),
    RestrictedDouble,
    RestrictedFloat,
    Sequence(Box<Type>),
    SignedLong,
    SignedLongLong,
    SignedShort,
    Symbol,
    USVString,
    Uint16Array,
    Uint32Array,
    Uint8Array,
    Uint8ClampedArray,
    Union(Vec<Box<Type>>),
    UnrestrictedDouble,
    UnrestrictedFloat,
    UnsignedLong,
    UnsignedLongLong,
    UnsignedShort,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Typedef {
    pub extended_attributes: Vec<Box<ExtendedAttribute>>,
    pub name: Identifier,
    pub type_: Box<Type>,
}

/// Consumes a vector of ASTs that are flattened into a single AST. This is helpful if you want to
/// merge ASTs from multiple files and be able to use the visitor pattern across all of them.
pub fn flatten_asts(asts: Vec<AST>) -> AST {
    asts.into_iter().flat_map(|ast| ast).collect()
}

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

    #[test]
    fn test_flatten_asts() {
        let ast1 = vec![
            Definition::Interface(Interface::NonPartial(NonPartialInterface {
                extended_attributes: vec![],
                inherits: None,
                members: vec![],
                name: "Node".to_string(),
            })),
        ];
        let ast2 = vec![
            Definition::Typedef(Typedef {
                extended_attributes: vec![],
                name: "Typedef".to_string(),
                type_: Box::new(Type {
                    extended_attributes: vec![],
                    kind: TypeKind::Any,
                    nullable: false,
                }),
            }),
        ];

        assert_eq!(
            flatten_asts(vec![ast1.clone(), ast2.clone()]),
            vec![ast1[0].clone(), ast2[0].clone()]
        );
    }
}
<|endoftext|>


<commit_before>use ascii::AsciiChar;

pub struct PascalStr {
    chars: [AsciiChar]
}
<commit_msg>Replace `PascalStr` internals with an `AsciiStr` for convenience. Also, various improvements.<commit_after>use ascii::{AsciiChar, AsciiStr};
use std::convert::AsRef;
use ::PASCAL_STRING_BUF_SIZE;

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub fn render() -> seed::dom_types::Node<Msg> {
    div![
        h1!["News"],
        br![],
        br![],
        br![],
        El::from_html("

Date	News

28th July 2019	bigprimes.net has been rewritten from the ground up using rust!
All archives have been retired in favour of client side processing in web assembly.

22nd January 2019	Ethereum bounty contracts have now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!

10th March 2018	Added torrents for the first million primes and first billion prime numbers.

12th November 2017	Site is now running on AWS Lambda, but can still fallback to regular VM hosting if ever needed. Site is now ~40% covered by unit tests.

13th November 2016	Site source code has been converted to PHP7 with Silex framework. Some methods have also been moved to cpp from PHP https://github.com/craigmayhew/bigprimes.net/

28th February 2014	You can now find the websites php source code here https://github.com/craigmayhew/bigprimes.net/

19th November 2011	Thank you to Yu Kwong Yiu Wilson for the donation!

13th July 2011	We are retiring the distributed computing client. Thank you all for your help and processing cycles.
        Watch this space for an open source GPU client coming soon...

10th February 2010	We have added a page that shows the sum of the digits of prime numbers (now retired).

1st February 2010	Thanks to everyone for donating computer time, we are now upto 1.4 billion primes. We now also have a facebook group where you get news updates and show your support for the project!

28th September 2009	Thanks for all your help! We made it to one billion prime numbers! Please keep on donating processor time as we still have plenty of storage for the prime numbers. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.

18th August 2009	It's been a while but we have been very busy. We've put together a distributed computing client written in javascript. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.

17th July 2008	We've now added a Forum (now retired) which can be found on the navigation links on the left.

14th July 2008	Someone named Kirk just emailed me to say the download links wern't working. I've now fixed this. Thanks Kirk!

4th July 2008	Added much faster code to the cruncher so that we can handle more of your page loads! Lots of little updates and some reorganizing of the site.

23rd June 2007	Added the Downloads section.

11th February 2007	Added the Fibonacci number archive containing the first 70331 Fibonacci numbers.

16th January 2007	Added the 44th Mersenne Prime number to the archive.

12th January 2007	The Archives are now more organized.

28th September 2005	We have managed to archive the first 100 million prime numbers.

20th May 2005	We have managed to archive the first 75 million prime numbers.

16th May 2005	We have managed to archive the first 50 million prime numbers.

14th May 2005	We have managed to archive the first 10 million prime numbers.

13th May 2005	We have managed to archive the first 1 million prime numbers.

"),
    ]
}<commit_msg>Replaced html with rust macros!<commit_after>use crate::Msg;
use seed::prelude::*;

pub fn render() -> seed::dom_types::Node<Msg> {
    div![
        h1!["News"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "text"},
            tbody![
                tr![
                    //TODO: change this to styles
                    td![attrs!{At::Width => "100"},"Date"],
                    td![attrs!{At::Width => "300"},"News"],
                ],
                tr![
                    td!["28th July 2019"],
                    td![El::from_html("bigprimes.net has been rewritten from the ground up using rust!
All archives have been retired in favour of client side processing in web assembly.")],
                ],
                tr![
                    td!["22nd January 2019"],
                    td![El::from_html("Ethereum bounty contracts have now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!")],
                ],
                tr![
                    td!["10th March 2018"],
                    td![El::from_html("Added torrents for the first million primes and first billion prime numbers.")],
                ],
                tr![
                    td!["12th November 2017"],
                    td![El::from_html("Site is now running on AWS Lambda, but can still fallback to regular VM hosting if ever needed. Site is now ~40% covered by unit tests.")],
                ],
                tr![
                    td!["13th November 2016"],
                    td![El::from_html("Site source code has been converted to PHP7 with Silex framework. Some methods have also been moved to cpp from PHP https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["28th February 2014"],
                    td![El::from_html("You can now find the websites php source code here https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["19th November 2011"],
                    td![El::from_html("Thank you to Yu Kwong Yiu Wilson for the donation!")],
                ],
                tr![
                    td!["13th July 2011"],
                    td![El::from_html("We are retiring the distributed computing client. Thank you all for your help and processing cycles.
        Watch this space for an open source GPU client coming soon...")],
                ],
                tr![
                    td!["10th February 2010"],
                    td![El::from_html("We have added a page that shows the sum of the digits of prime numbers (now retired).")],
                ],
                tr![
                    td!["1st February 2010"],
                    td![El::from_html("Thanks to everyone for donating computer time, we are now upto 1.4 billion primes. We now also have a facebook group where you get news updates and show your support for the project!")],
                ],
                tr![
                    td!["28th September 2009"],
                    td![El::from_html("Thanks for all your help! We made it to one billion prime numbers! Please keep on donating processor time as we still have plenty of storage for the prime numbers. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["18th August 2009"],
                    td![El::from_html("It's been a while but we have been very busy. We've put together a distributed computing client written in javascript. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["17th July 2008"],
                    td![El::from_html("We've now added a Forum (now retired) which can be found on the navigation links on the left.")],
                ],
                tr![
                    td!["14th July 2008"],
                    td![El::from_html("Someone named Kirk just emailed me to say the download links wern't working. I've now fixed this. Thanks Kirk!")],
                ],
                tr![
                    td!["4th July 2008"],
                    td![El::from_html("Added much faster code to the cruncher so that we can handle more of your page loads! Lots of little updates and some reorganizing of the site.")],
                ],
                tr![
                    td!["23rd June 2007"],
                    td![El::from_html("Added the Downloads section.")],
                ],
                tr![
                    td!["11th February 2007"],
                    td![El::from_html("Added the Fibonacci number archive containing the first 70331 Fibonacci numbers.")],
                ],
                tr![
                    td!["16th January 2007"],
                    td![El::from_html("Added the 44th Mersenne Prime number to the archive.")],
                ],
                tr![
                    td!["12th January 2007"],
                    td![El::from_html("The Archives are now more organized.")],
                ],
                tr![
                    td!["28th September 2005"],
                    td![El::from_html("We have managed to archive the first 100 million prime numbers.")],
                ],
                tr![
                    td!["20th May 2005"],
                    td![El::from_html("We have managed to archive the first 75 million prime numbers.")],
                ],
                tr![
                    td!["16th May 2005"],
                    td![El::from_html("We have managed to archive the first 50 million prime numbers.")],
                ],
                tr![
                    td!["14th May 2005"],
                    td![El::from_html("We have managed to archive the first 10 million prime numbers.")],
                ],
                tr![
                    td!["13th May 2005"],
                    td![El::from_html("We have managed to archive the first 1 million prime numbers.")],
                ],
            ],
        ],
    ]
}<|endoftext|>