<commit_before>#![allow(clippy::zero_sized_map_values)]

use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::{Deserialize, Serialize};
use serde_yaml::{Deserializer, Value};
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<'de, T>(yaml: &'de str, expected: &str)
where
    T: Deserialize<'de> + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_scan_error() {
    let yaml = ">\n@";
    let expected = "found character that cannot start any token at line 2 column 1, while scanning for the next token";
    test_error::<Value>(yaml, expected);
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_bytes() {
    let expected = "serialization and deserialization of bytes in YAML is not implemented";
    test_error::<&[u8]>("...", expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_serialize_nested_enum() {
    #[derive(Serialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Serialize, Debug)]
    enum Inner {
        Newtype(usize),
        Tuple(usize, usize),
        Struct { x: usize },
    }

    let expected = "serializing nested enums in YAML is not supported yet";

    let e = Outer::Inner(Inner::Newtype(0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Tuple(0, 0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Struct { x: 0 });
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);
}

#[test]
fn test_deserialize_nested_enum() {
    #[derive(Deserialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Deserialize, Debug)]
    enum Inner {
        Variant(Vec<usize>),
    }

    let yaml = indoc! {"
        ---
        !Inner []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Variant []
    "};
    let expected = "unknown variant `Variant`, expected `Inner`";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Inner !Variant []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_struct_from_sequence() {
    #[allow(dead_code)]
    #[derive(Deserialize, Debug)]
    struct Struct {
        x: usize,
        y: usize,
    }
    let yaml = indoc! {"
        [0, 0]
    "};
    let expected = "invalid type: sequence, expected struct Struct at position 0";
    test_error::<Struct>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "&a [0, *a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_newtype() {
    #[derive(Deserialize, Debug)]
    struct S(Option<Box<S>>);

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 513";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

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

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<commit_msg>Format with rustfmt 1.5.1-nightly<commit_after>#![allow(clippy::zero_sized_map_values)]

use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::{Deserialize, Serialize};
use serde_yaml::{Deserializer, Value};
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<'de, T>(yaml: &'de str, expected: &str)
where
    T: Deserialize<'de> + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_scan_error() {
    let yaml = ">\n@";
    let expected = "found character that cannot start any token at line 2 column 1, while scanning for the next token";
    test_error::<Value>(yaml, expected);
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_bytes() {
    let expected = "serialization and deserialization of bytes in YAML is not implemented";
    test_error::<&[u8]>("...", expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected =
        "did not find expected node content at line 4 column 1, while parsing a block node";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_serialize_nested_enum() {
    #[derive(Serialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Serialize, Debug)]
    enum Inner {
        Newtype(usize),
        Tuple(usize, usize),
        Struct { x: usize },
    }

    let expected = "serializing nested enums in YAML is not supported yet";

    let e = Outer::Inner(Inner::Newtype(0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Tuple(0, 0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Struct { x: 0 });
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);
}

#[test]
fn test_deserialize_nested_enum() {
    #[derive(Deserialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Deserialize, Debug)]
    enum Inner {
        Variant(Vec<usize>),
    }

    let yaml = indoc! {"
        ---
        !Inner []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Variant []
    "};
    let expected = "unknown variant `Variant`, expected `Inner`";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Inner !Variant []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_struct_from_sequence() {
    #[allow(dead_code)]
    #[derive(Deserialize, Debug)]
    struct Struct {
        x: usize,
        y: usize,
    }
    let yaml = indoc! {"
        [0, 0]
    "};
    let expected = "invalid type: sequence, expected struct Struct at position 0";
    test_error::<Struct>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "&a [0, *a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_newtype() {
    #[derive(Deserialize, Debug)]
    struct S(Option<Box<S>>);

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 513";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

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

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<|endoftext|>


<commit_before>#[doc = "

Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.

"];

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    _srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_mod: fold_mod,
        fold_const: fold_const,
        fold_fn: fold_fn,
        fold_enum: fold_enum
        with *fold::default_seq_fold(())
    });
    fold.fold_crate(fold, doc)
}

fn fold_mod(fold: fold::fold<()>, doc: doc::moddoc) -> doc::moddoc {
    let doc = fold::default_seq_fold_mod(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_const(fold: fold::fold<()>, doc: doc::constdoc) -> doc::constdoc {
    let doc = fold::default_seq_fold_const(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_fn(fold: fold::fold<()>, doc: doc::fndoc) -> doc::fndoc {
    let doc = fold::default_seq_fold_fn(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_enum(fold: fold::fold<()>, doc: doc::enumdoc) -> doc::enumdoc {
    let doc = fold::default_seq_fold_enum(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

#[test]
fn should_promote_mod_desc() {
    let source = "#[doc(desc = \"desc\")] mod m { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.mods[0].brief == some("desc");
    assert doc.topmod.mods[0].desc == none;
}

#[test]
fn should_promote_const_desc() {
    let source = "#[doc(desc = \"desc\")] const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.consts[0].brief == some("desc");
    assert doc.topmod.consts[0].desc == none;
}

#[test]
fn should_promote_fn_desc() {
    let source = "#[doc(desc = \"desc\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.fns[0].brief == some("desc");
    assert doc.topmod.fns[0].desc == none;
}

#[test]
fn should_promote_enum_desc() {
    let source = "#[doc(desc = \"desc\")] enum a { b }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.enums[0].brief == some("desc");
    assert doc.topmod.enums[0].desc == none;
}

fn modify(
    brief: option<str>,
    desc: option<str>
) -> (option<str>, option<str>) {

    if option::is_some(brief) || option::is_none(desc) {
        ret (brief, desc);
    }

    parse_desc(option::get(desc))
}

fn parse_desc(desc: str) -> (option<str>, option<str>) {

    const max_brief_len: uint = 120u;

    let paras = paragraphs(desc);

    if check vec::is_not_empty(paras) {
        let maybe_brief = vec::head(paras);
        if str::char_len(maybe_brief) <= max_brief_len {
            let desc_paras = vec::tail(paras);
            let desc = if vec::is_not_empty(desc_paras) {
                some(str::connect(desc_paras, "\n\n"))
            } else {
                none
            };
            (some(maybe_brief), desc)
        } else {
            (none, some(desc))
        }
    } else {
        (none, none)
    }
}

fn paragraphs(s: str) -> [str] {
    let lines = str::lines_any(s);
    let whitespace_lines = 0;
    let accum = "";
    let paras = vec::foldl([], lines) {|paras, line|
        let res = paras;

        if str::is_whitespace(line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if str::is_not_empty(accum) {
                    res += [accum];
                    accum = "";
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                line
            } else {
                accum + "\n" + line
            }
        }

        res
    };

    if str::is_not_empty(accum) {
        paras + [accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs("1\n\n2");
    assert paras == ["1", "2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs("\n\n1\n1\n\n2\n\n");
    assert paras == ["1\n1", "2"];
}

#[test]
fn should_promote_short_descs() {
    let brief = none;
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == desc;
    assert newdesc == none;
}

#[test]
fn should_not_promote_long_descs() {
    let brief = none;
    let desc = some("Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland.
The town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let (newbrief, _) = modify(brief, desc);
    assert newbrief == none;
}

#[test]
fn should_not_promote_descs_over_brief() {
    let brief = some("brief");
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == brief;
    assert newdesc == desc;
}

#[test]
fn should_extract_brief_from_desc() {
    let brief = none;
    let desc = some("brief\n\ndesc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == some("brief");
    assert newdesc == some("desc");
}
<commit_msg>rustdoc: Promote resource long descriptions to brief descriptions<commit_after>#[doc = "

Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.

"];

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    _srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_mod: fold_mod,
        fold_const: fold_const,
        fold_fn: fold_fn,
        fold_enum: fold_enum,
        fold_res: fold_res
        with *fold::default_seq_fold(())
    });
    fold.fold_crate(fold, doc)
}

fn fold_mod(fold: fold::fold<()>, doc: doc::moddoc) -> doc::moddoc {
    let doc = fold::default_seq_fold_mod(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_const(fold: fold::fold<()>, doc: doc::constdoc) -> doc::constdoc {
    let doc = fold::default_seq_fold_const(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_fn(fold: fold::fold<()>, doc: doc::fndoc) -> doc::fndoc {
    let doc = fold::default_seq_fold_fn(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_enum(fold: fold::fold<()>, doc: doc::enumdoc) -> doc::enumdoc {
    let doc = fold::default_seq_fold_enum(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

fn fold_res(fold: fold::fold<()>, doc: doc::resdoc) -> doc::resdoc {
    let doc = fold::default_seq_fold_res(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    ~{
        brief: brief,
        desc: desc
        with *doc
    }
}

#[test]
fn should_promote_mod_desc() {
    let source = "#[doc(desc = \"desc\")] mod m { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.mods[0].brief == some("desc");
    assert doc.topmod.mods[0].desc == none;
}

#[test]
fn should_promote_const_desc() {
    let source = "#[doc(desc = \"desc\")] const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.consts[0].brief == some("desc");
    assert doc.topmod.consts[0].desc == none;
}

#[test]
fn should_promote_fn_desc() {
    let source = "#[doc(desc = \"desc\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.fns[0].brief == some("desc");
    assert doc.topmod.fns[0].desc == none;
}

#[test]
fn should_promote_enum_desc() {
    let source = "#[doc(desc = \"desc\")] enum a { b }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.enums[0].brief == some("desc");
    assert doc.topmod.enums[0].desc == none;
}

#[test]
fn should_promote_resource_desc() {
    let source = "#[doc(desc = \"desc\")] resource r(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = attr_pass::mk_pass()(srv, doc);
    let doc = run(srv, doc);
    assert doc.topmod.resources[0].brief == some("desc");
    assert doc.topmod.resources[0].desc == none;
}

fn modify(
    brief: option<str>,
    desc: option<str>
) -> (option<str>, option<str>) {

    if option::is_some(brief) || option::is_none(desc) {
        ret (brief, desc);
    }

    parse_desc(option::get(desc))
}

fn parse_desc(desc: str) -> (option<str>, option<str>) {

    const max_brief_len: uint = 120u;

    let paras = paragraphs(desc);

    if check vec::is_not_empty(paras) {
        let maybe_brief = vec::head(paras);
        if str::char_len(maybe_brief) <= max_brief_len {
            let desc_paras = vec::tail(paras);
            let desc = if vec::is_not_empty(desc_paras) {
                some(str::connect(desc_paras, "\n\n"))
            } else {
                none
            };
            (some(maybe_brief), desc)
        } else {
            (none, some(desc))
        }
    } else {
        (none, none)
    }
}

fn paragraphs(s: str) -> [str] {
    let lines = str::lines_any(s);
    let whitespace_lines = 0;
    let accum = "";
    let paras = vec::foldl([], lines) {|paras, line|
        let res = paras;

        if str::is_whitespace(line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if str::is_not_empty(accum) {
                    res += [accum];
                    accum = "";
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                line
            } else {
                accum + "\n" + line
            }
        }

        res
    };

    if str::is_not_empty(accum) {
        paras + [accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs("1\n\n2");
    assert paras == ["1", "2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs("\n\n1\n1\n\n2\n\n");
    assert paras == ["1\n1", "2"];
}

#[test]
fn should_promote_short_descs() {
    let brief = none;
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == desc;
    assert newdesc == none;
}

#[test]
fn should_not_promote_long_descs() {
    let brief = none;
    let desc = some("Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland.
The town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let (newbrief, _) = modify(brief, desc);
    assert newbrief == none;
}

#[test]
fn should_not_promote_descs_over_brief() {
    let brief = some("brief");
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == brief;
    assert newdesc == desc;
}

#[test]
fn should_extract_brief_from_desc() {
    let brief = none;
    let desc = some("brief\n\ndesc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == some("brief");
    assert newdesc == some("desc");
}
<|endoftext|>


<commit_before>#[doc = "

Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.

"];

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    _srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_mod: fold_mod,
        fold_const: fold_const,
        fold_fn: fold_fn,
        fold_enum: fold_enum,
        fold_res: fold_res,
        fold_iface: fold_iface,
        fold_impl: fold_impl,
        fold_type: fold_type
        with *fold::default_seq_fold(())
    });
    fold.fold_crate(fold, doc)
}

fn fold_mod(fold: fold::fold<()>, doc: doc::moddoc) -> doc::moddoc {
    let doc = fold::default_seq_fold_mod(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

fn fold_const(fold: fold::fold<()>, doc: doc::constdoc) -> doc::constdoc {
    let doc = fold::default_seq_fold_const(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

fn fold_fn(fold: fold::fold<()>, doc: doc::fndoc) -> doc::fndoc {
    let doc = fold::default_seq_fold_fn(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

fn fold_enum(fold: fold::fold<()>, doc: doc::enumdoc) -> doc::enumdoc {
    let doc = fold::default_seq_fold_enum(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

fn fold_res(fold: fold::fold<()>, doc: doc::resdoc) -> doc::resdoc {
    let doc = fold::default_seq_fold_res(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
    let doc =fold::default_seq_fold_iface(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        },
        methods: vec::map(doc.methods) {|doc|
            let (brief, desc) = modify(doc.brief, doc.desc);

            {
                brief: brief,
                desc: desc
                with doc
            }
        }
        with doc
    }
}

fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
    let doc =fold::default_seq_fold_impl(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        },
        methods: vec::map(doc.methods) {|doc|
            let (brief, desc) = modify(doc.brief, doc.desc);

            {
                brief: brief,
                desc: desc
                with doc
            }
        }
        with doc
    }
}

fn fold_type(fold: fold::fold<()>, doc: doc::tydoc) -> doc::tydoc {
    let doc = fold::default_seq_fold_type(fold, doc);
    let (brief, desc) = modify(doc.brief(), doc.desc());

    {
        item: {
            brief: brief,
            desc: desc
            with doc.item
        }
        with doc
    }
}

#[test]
fn should_promote_mod_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }");
    assert doc.topmod.mods()[0].brief() == some("desc");
    assert doc.topmod.mods()[0].desc() == none;
}

#[test]
fn should_promote_const_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] const a: bool = true;");
    assert doc.topmod.consts()[0].brief() == some("desc");
    assert doc.topmod.consts()[0].desc() == none;
}

#[test]
fn should_promote_fn_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] fn a() { }");
    assert doc.topmod.fns()[0].brief() == some("desc");
    assert doc.topmod.fns()[0].desc() == none;
}

#[test]
fn should_promote_enum_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] enum a { b }");
    assert doc.topmod.enums()[0].brief() == some("desc");
    assert doc.topmod.enums()[0].desc() == none;
}

#[test]
fn should_promote_resource_desc() {
    let doc = test::mk_doc(
        "#[doc(desc = \"desc\")] resource r(a: bool) { }");
    assert doc.topmod.resources()[0].brief() == some("desc");
    assert doc.topmod.resources()[0].desc() == none;
}

#[test]
fn should_promote_iface_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] iface i { fn a(); }");
    assert doc.topmod.ifaces()[0].brief() == some("desc");
    assert doc.topmod.ifaces()[0].desc() == none;
}

#[test]
fn should_promote_iface_method_desc() {
    let doc = test::mk_doc("iface i { #[doc(desc = \"desc\")] fn a(); }");
    assert doc.topmod.ifaces()[0].methods[0].brief == some("desc");
    assert doc.topmod.ifaces()[0].methods[0].desc == none;
}

#[test]
fn should_promote_impl_desc() {
    let doc = test::mk_doc(
        "#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
    assert doc.topmod.impls()[0].brief() == some("desc");
    assert doc.topmod.impls()[0].desc() == none;
}

#[test]
fn should_promote_impl_method_desc() {
    let doc = test::mk_doc(
        "impl i for int { #[doc(desc = \"desc\")] fn a() { } }");
    assert doc.topmod.impls()[0].methods[0].brief == some("desc");
    assert doc.topmod.impls()[0].methods[0].desc == none;
}

#[test]
fn should_promote_type_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] type t = int;");
    assert doc.topmod.types()[0].brief() == some("desc");
    assert doc.topmod.types()[0].desc() == none;
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::cratedoc {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        let doc = attr_pass::mk_pass()(srv, doc);
        run(srv, doc)
    }
}

fn modify(
    brief: option<str>,
    desc: option<str>
) -> (option<str>, option<str>) {

    if option::is_some(brief) || option::is_none(desc) {
        ret (brief, desc);
    }

    parse_desc(option::get(desc))
}

fn parse_desc(desc: str) -> (option<str>, option<str>) {

    const max_brief_len: uint = 120u;

    let paras = paragraphs(desc);

    if check vec::is_not_empty(paras) {
        let maybe_brief = vec::head(paras);
        if str::len(maybe_brief) <= max_brief_len {
            let desc_paras = vec::tail(paras);
            let desc = if vec::is_not_empty(desc_paras) {
                some(str::connect(desc_paras, "\n\n"))
            } else {
                none
            };
            (some(maybe_brief), desc)
        } else {
            (none, some(desc))
        }
    } else {
        (none, none)
    }
}

fn paragraphs(s: str) -> [str] {
    let lines = str::lines_any(s);
    let whitespace_lines = 0;
    let accum = "";
    let paras = vec::foldl([], lines) {|paras, line|
        let res = paras;

        if str::is_whitespace(line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if str::is_not_empty(accum) {
                    res += [accum];
                    accum = "";
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                line
            } else {
                accum + "\n" + line
            }
        }

        res
    };

    if str::is_not_empty(accum) {
        paras + [accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs("1\n\n2");
    assert paras == ["1", "2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs("\n\n1\n1\n\n2\n\n");
    assert paras == ["1\n1", "2"];
}

#[test]
fn should_promote_short_descs() {
    let brief = none;
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == desc;
    assert newdesc == none;
}

#[test]
fn should_not_promote_long_descs() {
    let brief = none;
    let desc = some("Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland.
The town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let (newbrief, _) = modify(brief, desc);
    assert newbrief == none;
}

#[test]
fn should_not_promote_descs_over_brief() {
    let brief = some("brief");
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == brief;
    assert newdesc == desc;
}

#[test]
fn should_extract_brief_from_desc() {
    let brief = none;
    let desc = some("brief\n\ndesc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == some("brief");
    assert newdesc == some("desc");
}
<commit_msg>rustdoc: Simplify desc_to_brief pass<commit_after>#[doc = "

Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.

"];

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    _srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_item: fold_item,
        fold_iface: fold_iface,
        fold_impl: fold_impl
        with *fold::default_seq_fold(())
    });
    fold.fold_crate(fold, doc)
}

fn fold_item(fold: fold::fold<()>, doc: doc::itemdoc) -> doc::itemdoc {
    let doc = fold::default_seq_fold_item(fold, doc);
    let (brief, desc) = modify(doc.brief, doc.desc);

    {
        brief: brief,
        desc: desc
        with doc
    }
}

fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
    let doc =fold::default_seq_fold_iface(fold, doc);

    {
        methods: vec::map(doc.methods) {|doc|
            let (brief, desc) = modify(doc.brief, doc.desc);

            {
                brief: brief,
                desc: desc
                with doc
            }
        }
        with doc
    }
}

fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
    let doc =fold::default_seq_fold_impl(fold, doc);

    {
        methods: vec::map(doc.methods) {|doc|
            let (brief, desc) = modify(doc.brief, doc.desc);

            {
                brief: brief,
                desc: desc
                with doc
            }
        }
        with doc
    }
}

#[test]
fn should_promote_mod_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }");
    assert doc.topmod.mods()[0].brief() == some("desc");
    assert doc.topmod.mods()[0].desc() == none;
}

#[test]
fn should_promote_const_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] const a: bool = true;");
    assert doc.topmod.consts()[0].brief() == some("desc");
    assert doc.topmod.consts()[0].desc() == none;
}

#[test]
fn should_promote_fn_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] fn a() { }");
    assert doc.topmod.fns()[0].brief() == some("desc");
    assert doc.topmod.fns()[0].desc() == none;
}

#[test]
fn should_promote_enum_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] enum a { b }");
    assert doc.topmod.enums()[0].brief() == some("desc");
    assert doc.topmod.enums()[0].desc() == none;
}

#[test]
fn should_promote_resource_desc() {
    let doc = test::mk_doc(
        "#[doc(desc = \"desc\")] resource r(a: bool) { }");
    assert doc.topmod.resources()[0].brief() == some("desc");
    assert doc.topmod.resources()[0].desc() == none;
}

#[test]
fn should_promote_iface_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] iface i { fn a(); }");
    assert doc.topmod.ifaces()[0].brief() == some("desc");
    assert doc.topmod.ifaces()[0].desc() == none;
}

#[test]
fn should_promote_iface_method_desc() {
    let doc = test::mk_doc("iface i { #[doc(desc = \"desc\")] fn a(); }");
    assert doc.topmod.ifaces()[0].methods[0].brief == some("desc");
    assert doc.topmod.ifaces()[0].methods[0].desc == none;
}

#[test]
fn should_promote_impl_desc() {
    let doc = test::mk_doc(
        "#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
    assert doc.topmod.impls()[0].brief() == some("desc");
    assert doc.topmod.impls()[0].desc() == none;
}

#[test]
fn should_promote_impl_method_desc() {
    let doc = test::mk_doc(
        "impl i for int { #[doc(desc = \"desc\")] fn a() { } }");
    assert doc.topmod.impls()[0].methods[0].brief == some("desc");
    assert doc.topmod.impls()[0].methods[0].desc == none;
}

#[test]
fn should_promote_type_desc() {
    let doc = test::mk_doc("#[doc(desc = \"desc\")] type t = int;");
    assert doc.topmod.types()[0].brief() == some("desc");
    assert doc.topmod.types()[0].desc() == none;
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::cratedoc {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        let doc = attr_pass::mk_pass()(srv, doc);
        run(srv, doc)
    }
}

fn modify(
    brief: option<str>,
    desc: option<str>
) -> (option<str>, option<str>) {

    if option::is_some(brief) || option::is_none(desc) {
        ret (brief, desc);
    }

    parse_desc(option::get(desc))
}

fn parse_desc(desc: str) -> (option<str>, option<str>) {

    const max_brief_len: uint = 120u;

    let paras = paragraphs(desc);

    if check vec::is_not_empty(paras) {
        let maybe_brief = vec::head(paras);
        if str::len(maybe_brief) <= max_brief_len {
            let desc_paras = vec::tail(paras);
            let desc = if vec::is_not_empty(desc_paras) {
                some(str::connect(desc_paras, "\n\n"))
            } else {
                none
            };
            (some(maybe_brief), desc)
        } else {
            (none, some(desc))
        }
    } else {
        (none, none)
    }
}

fn paragraphs(s: str) -> [str] {
    let lines = str::lines_any(s);
    let whitespace_lines = 0;
    let accum = "";
    let paras = vec::foldl([], lines) {|paras, line|
        let res = paras;

        if str::is_whitespace(line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if str::is_not_empty(accum) {
                    res += [accum];
                    accum = "";
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                line
            } else {
                accum + "\n" + line
            }
        }

        res
    };

    if str::is_not_empty(accum) {
        paras + [accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs("1\n\n2");
    assert paras == ["1", "2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs("\n\n1\n1\n\n2\n\n");
    assert paras == ["1\n1", "2"];
}

#[test]
fn should_promote_short_descs() {
    let brief = none;
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == desc;
    assert newdesc == none;
}

#[test]
fn should_not_promote_long_descs() {
    let brief = none;
    let desc = some("Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland.
The town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let (newbrief, _) = modify(brief, desc);
    assert newbrief == none;
}

#[test]
fn should_not_promote_descs_over_brief() {
    let brief = some("brief");
    let desc = some("desc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == brief;
    assert newdesc == desc;
}

#[test]
fn should_extract_brief_from_desc() {
    let brief = none;
    let desc = some("brief\n\ndesc");
    let (newbrief, newdesc) = modify(brief, desc);
    assert newbrief == some("brief");
    assert newdesc == some("desc");
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate static_assertions;

trait Tri<A: ?Sized, B: ?Sized, C: ?Sized> {}

impl<T, A: ?Sized, B: ?Sized, C: ?Sized> Tri<A, B, C> for T {}

assert_impl!(tri; u64, Tri<[&'static u8], Send, (u16, u16)>);
assert_impl!(byte; u8, Send, Sync);
assert_impl!(iter; &[u8], IntoIterator /* TODO: <Item=&u8> */);
assert_impl!(slice; [u8], Send, Sync, AsRef<[u8]>);

#[cfg(feature = "failure")]
assert_impl!(ptr; *const u8, Send, Sync);

#[test]
fn str_impl() {
    assert_impl!(str, Send, Sync, AsRef<[u8]>);
}
<commit_msg>[Tests] Make assert_impl test even more obscure<commit_after>#![no_std]

#[macro_use]
extern crate static_assertions;

trait Tri<A: ?Sized, B: ?Sized, C: ?Sized> {}

impl<T, A: ?Sized, B: ?Sized, C: ?Sized> Tri<A, B, C> for T {}

assert_impl!(tri; u64, Tri<[&'static u8], Tri<Send, Sync, str>, (u16, u16)>);
assert_impl!(byte; u8, Send, Sync);
assert_impl!(iter; &[u8], IntoIterator /* TODO: <Item=&u8> */);
assert_impl!(slice; [u8], Send, Sync, AsRef<[u8]>);

#[cfg(feature = "failure")]
assert_impl!(ptr; *const u8, Send, Sync);

#[test]
fn str_impl() {
    assert_impl!(str, Send, Sync, AsRef<[u8]>);
}
<|endoftext|>


<commit_before>#![feature(tool_lints)]

#![allow(unused, clippy::many_single_char_names)]
#![warn(clippy::ptr_arg)]

use std::borrow::Cow;

fn do_vec(x: &Vec<i64>) {
    //Nothing here
}

fn do_vec_mut(x: &mut Vec<i64>) { // no error here
    //Nothing here
}

fn do_str(x: &String) {
    //Nothing here either
}

fn do_str_mut(x: &mut String) { // no error here
    //Nothing here either
}

fn main() {
}

trait Foo {
    type Item;
    fn do_vec(x: &Vec<i64>);
    fn do_item(x: &Self::Item);
}

struct Bar;

// no error, in trait impl (#425)
impl Foo for Bar {
    type Item = Vec<u8>;
    fn do_vec(x: &Vec<i64>) {}
    fn do_item(x: &Vec<u8>) {}
}

fn cloned(x: &Vec<u8>) -> Vec<u8> {
    let e = x.clone();
    let f = e.clone(); // OK
    let g = x;
    let h = g.clone(); // Alas, we cannot reliably detect this without following data.
    let i = (e).clone();
    x.clone()
}

fn str_cloned(x: &String) -> String {
    let a = x.clone();
    let b = x.clone();
    let c = b.clone();
    let d = a.clone()
             .clone()
             .clone();
    x.clone()
}

fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    let a = x.capacity();
    let b = y.clone();
    let c = y.as_str();
}

fn false_positive_capacity_too(x: &String) -> String {
    if x.capacity() > 1024 { panic!("Too large!"); }
    x.clone()
}

#[allow(dead_code)]
fn test_cow_with_ref(c: &Cow<[i32]>) {
}

#[allow(dead_code)]
fn test_cow(c: Cow<[i32]>) {
    let _c = c;
}
<commit_msg>Added test case for ptr_arg<commit_after>#![feature(tool_lints)]

#![allow(unused, clippy::many_single_char_names)]
#![warn(clippy::ptr_arg)]

use std::borrow::Cow;

fn do_vec(x: &Vec<i64>) {
    //Nothing here
}

fn do_vec_mut(x: &mut Vec<i64>) { // no error here
    //Nothing here
}

fn do_str(x: &String) {
    //Nothing here either
}

fn do_str_mut(x: &mut String) { // no error here
    //Nothing here either
}

fn main() {
}

trait Foo {
    type Item;
    fn do_vec(x: &Vec<i64>);
    fn do_item(x: &Self::Item);
}

struct Bar;

// no error, in trait impl (#425)
impl Foo for Bar {
    type Item = Vec<u8>;
    fn do_vec(x: &Vec<i64>) {}
    fn do_item(x: &Vec<u8>) {}
}

fn cloned(x: &Vec<u8>) -> Vec<u8> {
    let e = x.clone();
    let f = e.clone(); // OK
    let g = x;
    let h = g.clone(); // Alas, we cannot reliably detect this without following data.
    let i = (e).clone();
    x.clone()
}

fn str_cloned(x: &String) -> String {
    let a = x.clone();
    let b = x.clone();
    let c = b.clone();
    let d = a.clone()
             .clone()
             .clone();
    x.clone()
}

fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    let a = x.capacity();
    let b = y.clone();
    let c = y.as_str();
}

fn false_positive_capacity_too(x: &String) -> String {
    if x.capacity() > 1024 { panic!("Too large!"); }
    x.clone()
}

#[allow(dead_code)]
fn test_cow_with_ref(c: &Cow<[i32]>) {
}

#[allow(dead_code)]
fn test_cow(c: Cow<[i32]>) {
    let _c = c;
}

trait Foo2 {
    fn do_string(&self);
}

// no error for &self references where self is of type String (#2293)
impl Foo2 for String { fn do_string(&self) {} }
<|endoftext|>


<commit_before>use crate::{
    analysis::{
        conversion_type::ConversionType, function_parameters::CParameter,
        functions::is_carray_with_direct_elements, imports::Imports, ref_mode::RefMode,
        return_value, rust_type::parameter_rust_type,
    },
    config,
    env::Env,
    library::*,
    nameutil,
};
use log::error;
use std::slice::Iter;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
    None,
    Normal,
    Optional,
    Combined,
    //<use function return>
    Throws(bool),
}

impl Default for Mode {
    fn default() -> Mode {
        Mode::None
    }
}

#[derive(Debug, Default)]
pub struct Info {
    pub mode: Mode,
    pub params: Vec<Parameter>,
}

impl Info {
    pub fn is_empty(&self) -> bool {
        self.mode == Mode::None
    }

    pub fn iter(&self) -> Iter<'_, Parameter> {
        self.params.iter()
    }
}

pub fn analyze(
    env: &Env,
    func: &Function,
    func_c_params: &[CParameter],
    func_ret: &return_value::Info,
    configured_functions: &[&config::functions::Function],
) -> (Info, bool) {
    let mut info: Info = Default::default();
    let mut unsupported_outs = false;

    let nullable_override = configured_functions
        .iter()
        .filter_map(|f| f.ret.nullable)
        .next();
    if func.throws {
        let use_ret = use_return_value_for_result(env, func_ret, &func.name, configured_functions);
        info.mode = Mode::Throws(use_ret);
    } else if func.ret.typ == TypeId::tid_none() {
        info.mode = Mode::Normal;
    } else if func.ret.typ == TypeId::tid_bool() {
        if nullable_override == Some(Nullable(false)) {
            info.mode = Mode::Combined;
        } else {
            info.mode = Mode::Optional;
        }
    } else {
        info.mode = Mode::Combined;
    }

    for par in &func.parameters {
        if par.direction != ParameterDirection::Out {
            continue;
        }
        if can_as_return(env, par) {
            let mut par = par.clone();
            par.name = nameutil::mangle_keywords(&*par.name).into_owned();
            //TODO: temporary solution for string_type override
            if let Some(c_par) = func_c_params.iter().find(|c_par| c_par.name == par.name) {
                par.typ = c_par.typ;
            }
            info.params.push(par);
        } else {
            unsupported_outs = true;
        }
    }

    if info.params.is_empty() {
        info.mode = Mode::None;
    }
    if info.mode == Mode::Combined || info.mode == Mode::Throws(true) {
        let mut ret = func.ret.clone();
        //TODO: fully switch to use analyzed returns (it add too many Return<Option<>>)
        if let Some(ref par) = func_ret.parameter {
            ret.typ = par.typ;
        }
        if let Some(val) = nullable_override {
            ret.nullable = val;
        }
        info.params.insert(0, ret);
    }

    (info, unsupported_outs)
}

pub fn analyze_imports(env: &Env, parameters: &[Parameter], imports: &mut Imports) {
    for par in parameters {
        if par.direction == ParameterDirection::Out {
            match *env.library.type_(par.typ) {
                Type::Bitfield(..) | Type::Enumeration(..) => imports.add("std::mem"),
                Type::Fundamental(fund)
                    if fund != Fundamental::Utf8
                        && fund != Fundamental::OsString
                        && fund != Fundamental::Filename =>
                {
                    imports.add("std::mem")
                }
                _ if !par.caller_allocates => match ConversionType::of(env, par.typ) {
                    ConversionType::Direct | ConversionType::Scalar => (),
                    _ => imports.add("std::ptr"),
                },
                _ => (),
            }
        }
    }
}

pub fn can_as_return(env: &Env, par: &Parameter) -> bool {
    use super::conversion_type::ConversionType::*;
    match ConversionType::of(env, par.typ) {
        Direct => true,
        Scalar => true,
        Pointer => {
            // Disallow fundamental arrays without length
            if is_carray_with_direct_elements(env, par.typ) && par.array_length.is_none() {
                return false;
            }

            parameter_rust_type(
                env,
                par.typ,
                ParameterDirection::Out,
                Nullable(false),
                RefMode::None,
                par.scope,
            )
            .is_ok()
        }
        Borrow => false,
        Unknown => false,
    }
}

pub fn use_return_value_for_result(
    env: &Env,
    ret: &return_value::Info,
    func_name: &str,
    configured_functions: &[&config::functions::Function],
) -> bool {
    let typ = ret.parameter.as_ref().map(|x| x.typ).unwrap_or_default();
    use_function_return_for_result(env, typ, func_name, configured_functions)
}

pub fn use_function_return_for_result(
    env: &Env,
    typ: TypeId,
    func_name: &str,
    configured_functions: &[&config::functions::Function],
) -> bool {
    // Configuration takes precendence over everything.
    let use_return_for_result = configured_functions
        .iter()
        .filter_map(|f| f.ret.use_return_for_result.as_ref())
        .next();
    if let Some(use_return_for_result) = use_return_for_result {
        if typ == Default::default() {
            error!("Function \"{}\": use_return_for_result set to true, but function has no return value", func_name);
            return false;
        }
        return *use_return_for_result;
    }

    if typ == Default::default() {
        return false;
    }
    if typ.ns_id != INTERNAL_NAMESPACE {
        return true;
    }
    let type_ = env.type_(typ);
    !matches!(&*type_.get_name(), "UInt" | "Boolean")
}
<commit_msg>Consider nullability overrides for out parameters too<commit_after>use crate::{
    analysis::{
        conversion_type::ConversionType, function_parameters::CParameter,
        functions::is_carray_with_direct_elements, imports::Imports, ref_mode::RefMode,
        return_value, rust_type::parameter_rust_type,
    },
    config,
    env::Env,
    library::*,
    nameutil,
};
use log::error;
use std::slice::Iter;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
    None,
    Normal,
    Optional,
    Combined,
    //<use function return>
    Throws(bool),
}

impl Default for Mode {
    fn default() -> Mode {
        Mode::None
    }
}

#[derive(Debug, Default)]
pub struct Info {
    pub mode: Mode,
    pub params: Vec<Parameter>,
}

impl Info {
    pub fn is_empty(&self) -> bool {
        self.mode == Mode::None
    }

    pub fn iter(&self) -> Iter<'_, Parameter> {
        self.params.iter()
    }
}

pub fn analyze(
    env: &Env,
    func: &Function,
    func_c_params: &[CParameter],
    func_ret: &return_value::Info,
    configured_functions: &[&config::functions::Function],
) -> (Info, bool) {
    let mut info: Info = Default::default();
    let mut unsupported_outs = false;

    let nullable_override = configured_functions
        .iter()
        .filter_map(|f| f.ret.nullable)
        .next();
    if func.throws {
        let use_ret = use_return_value_for_result(env, func_ret, &func.name, configured_functions);
        info.mode = Mode::Throws(use_ret);
    } else if func.ret.typ == TypeId::tid_none() {
        info.mode = Mode::Normal;
    } else if func.ret.typ == TypeId::tid_bool() {
        if nullable_override == Some(Nullable(false)) {
            info.mode = Mode::Combined;
        } else {
            info.mode = Mode::Optional;
        }
    } else {
        info.mode = Mode::Combined;
    }

    for par in &func.parameters {
        if par.direction != ParameterDirection::Out {
            continue;
        }
        if can_as_return(env, par) {
            let mut par = par.clone();
            par.name = nameutil::mangle_keywords(&*par.name).into_owned();
            // FIXME: temporary solution for string_type, nullable override. This should completely
            // work based on the analyzed parameters instead of the library parameters.
            if let Some(c_par) = func_c_params.iter().find(|c_par| c_par.name == par.name) {
                par.typ = c_par.typ;
                par.nullable = c_par.nullable;
            }
            info.params.push(par);
        } else {
            unsupported_outs = true;
        }
    }

    if info.params.is_empty() {
        info.mode = Mode::None;
    }
    if info.mode == Mode::Combined || info.mode == Mode::Throws(true) {
        let mut ret = func.ret.clone();
        //TODO: fully switch to use analyzed returns (it add too many Return<Option<>>)
        if let Some(ref par) = func_ret.parameter {
            ret.typ = par.typ;
        }
        if let Some(val) = nullable_override {
            ret.nullable = val;
        }
        info.params.insert(0, ret);
    }

    (info, unsupported_outs)
}

pub fn analyze_imports(env: &Env, parameters: &[Parameter], imports: &mut Imports) {
    for par in parameters {
        if par.direction == ParameterDirection::Out {
            match *env.library.type_(par.typ) {
                Type::Bitfield(..) | Type::Enumeration(..) => imports.add("std::mem"),
                Type::Fundamental(fund)
                    if fund != Fundamental::Utf8
                        && fund != Fundamental::OsString
                        && fund != Fundamental::Filename =>
                {
                    imports.add("std::mem")
                }
                _ if !par.caller_allocates => match ConversionType::of(env, par.typ) {
                    ConversionType::Direct | ConversionType::Scalar => (),
                    _ => imports.add("std::ptr"),
                },
                _ => (),
            }
        }
    }
}

pub fn can_as_return(env: &Env, par: &Parameter) -> bool {
    use super::conversion_type::ConversionType::*;
    match ConversionType::of(env, par.typ) {
        Direct => true,
        Scalar => true,
        Pointer => {
            // Disallow fundamental arrays without length
            if is_carray_with_direct_elements(env, par.typ) && par.array_length.is_none() {
                return false;
            }

            parameter_rust_type(
                env,
                par.typ,
                ParameterDirection::Out,
                Nullable(false),
                RefMode::None,
                par.scope,
            )
            .is_ok()
        }
        Borrow => false,
        Unknown => false,
    }
}

pub fn use_return_value_for_result(
    env: &Env,
    ret: &return_value::Info,
    func_name: &str,
    configured_functions: &[&config::functions::Function],
) -> bool {
    let typ = ret.parameter.as_ref().map(|x| x.typ).unwrap_or_default();
    use_function_return_for_result(env, typ, func_name, configured_functions)
}

pub fn use_function_return_for_result(
    env: &Env,
    typ: TypeId,
    func_name: &str,
    configured_functions: &[&config::functions::Function],
) -> bool {
    // Configuration takes precendence over everything.
    let use_return_for_result = configured_functions
        .iter()
        .filter_map(|f| f.ret.use_return_for_result.as_ref())
        .next();
    if let Some(use_return_for_result) = use_return_for_result {
        if typ == Default::default() {
            error!("Function \"{}\": use_return_for_result set to true, but function has no return value", func_name);
            return false;
        }
        return *use_return_for_result;
    }

    if typ == Default::default() {
        return false;
    }
    if typ.ns_id != INTERNAL_NAMESPACE {
        return true;
    }
    let type_ = env.type_(typ);
    !matches!(&*type_.get_name(), "UInt" | "Boolean")
}
<|endoftext|>


<commit_before>use {AutoreleasePool, Backend, QueueFamily};
use internal::Channel;
use native;
use device::{Device, PhysicalDevice};

use std::{fmt, ops};
use std::sync::{Arc, Mutex, RwLock};

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use metal;
use objc::runtime::{Object};
use core_graphics::base::CGFloat;
use core_graphics::geometry::CGRect;
use cocoa::foundation::{NSRect};

pub type CAMetalLayer = *mut Object;
pub type CADrawable = *mut Object;

pub struct Surface {
    pub(crate) inner: Arc<SurfaceInner>,
    pub(crate) apply_pixel_scale: bool,
}

pub(crate) struct SurfaceInner {
    pub(crate) nsview: *mut Object,
    pub(crate) render_layer: Mutex<CAMetalLayer>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.nsview, release]; }
    }
}

pub struct SwapchainInner {
    frames: Vec<Option<(CADrawable, metal::Texture)>>,
}

impl ops::Index<hal::FrameImage> for SwapchainInner {
    type Output = metal::TextureRef;
    fn index(&self, index: hal::FrameImage) -> &Self::Output {
        self.frames[index as usize]
            .as_ref()
            .map(|&(_, ref tex)| tex)
            .expect("Frame texture is not resident!")
    }
}

unsafe impl Send for SwapchainInner {}
unsafe impl Sync for SwapchainInner {}

impl fmt::Debug for SwapchainInner {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Swapchain with {} image", self.frames.len())
    }
}

impl Drop for SwapchainInner {
    fn drop(&mut self) {
        for maybe in self.frames.drain(..) {
            if let Some((drawable, _)) = maybe {
                unsafe {
                    msg_send![drawable, release];
                }
            }
        }
    }
}

pub struct Swapchain {
    inner: Arc<RwLock<SwapchainInner>>,
    surface: Arc<SurfaceInner>,
    _size_pixels: (u64, u64),
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}

impl Swapchain {
    pub(crate) fn present(&self, index: hal::FrameImage) {
        let (drawable, _) = self.inner
            .write()
            .unwrap()
            .frames[index as usize]
            .take()
            .expect("Frame is not ready to present!");
        unsafe {
            msg_send![drawable, present];
            msg_send![drawable, release];
        }
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let (width, height) = self.pixel_dimensions();

        image::Kind::D2(width, height, 1, 1)
    }

    fn compatibility(
        &self, _: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>, Vec<hal::PresentMode>) {
        let render_layer_borrow = self.inner.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let max_frames: u64 = unsafe {
            msg_send![render_layer, maximumDrawableCount]
        };

        let caps = hal::SurfaceCapabilities {
            image_count: 1 .. max_frames as hal::FrameImage,
            current_extent: None,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
        };

        let formats = vec![
            format::Format::Bgra8Unorm,
            format::Format::Bgra8Srgb,
            format::Format::Rgba16Float,
        ];
        let present_modes = vec![
            hal::PresentMode::Fifo,
            hal::PresentMode::Immediate,
        ];

        (caps, Some(formats), present_modes)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true // TODO: Not sure this is the case, don't know associativity of IOSurface
    }
}

impl Surface {
    fn pixel_dimensions(&self) -> (image::Size, image::Size) {
        unsafe {
            // NSView bounds are measured in DIPs
            let bounds: NSRect = msg_send![self.inner.nsview, bounds];
            let bounds_pixel: NSRect = msg_send![self.inner.nsview, convertRectToBacking:bounds];
            (bounds_pixel.size.width as _, bounds_pixel.size.height as _)
        }
    }
}

impl Device {
    pub(crate) fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        let mtl_format = self.private_caps
            .map_format(config.color_format)
            .expect("unsupported backbuffer format");

        let render_layer_borrow = surface.inner.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let nsview = surface.inner.nsview;
        let format_desc = config.color_format.surface_desc();
        let framebuffer_only = config.image_usage == image::Usage::COLOR_ATTACHMENT;
        let display_sync = match config.present_mode {
            hal::PresentMode::Immediate => false,
            _ => true,
        };
        let device = self.shared.device.lock().unwrap();
        let device_raw: &metal::DeviceRef = &*device;

        let (view_size, scale_factor) = unsafe {
            msg_send![render_layer, setDevice: device_raw];
            msg_send![render_layer, setPixelFormat: mtl_format];
            msg_send![render_layer, setFramebufferOnly: framebuffer_only];
            //TODO: only set it where supported
            msg_send![render_layer, setDisplaySyncEnabled: display_sync];

            // Update render layer size
            let view_points_size: CGRect = msg_send![nsview, bounds];
            msg_send![render_layer, setBounds: view_points_size];

            let view_window: *mut Object = msg_send![nsview, window];
            if view_window.is_null() {
                panic!("surface is not attached to a window");
            }
            let scale_factor: CGFloat = if surface.apply_pixel_scale {
                msg_send![view_window, backingScaleFactor]
            } else {
                1.0
            };
            msg_send![render_layer, setContentsScale: scale_factor];
            info!("view points size {:?} scale factor {:?}", view_points_size, scale_factor);
            (view_points_size.size, scale_factor)
        };

        let pixel_width = (view_size.width * scale_factor) as u64;
        let pixel_height = (view_size.height * scale_factor) as u64;

        let inner = SwapchainInner {
            frames: (0 .. config.image_count).map(|_| None).collect(),
        };

        let swapchain = Swapchain {
            inner: Arc::new(RwLock::new(inner)),
            surface: surface.inner.clone(),
            _size_pixels: (pixel_width, pixel_height),
        };

        let images = (0 .. config.image_count)
            .map(|index| native::Image {
                root: native::ImageRoot::Frame(native::Frame {
                    swapchain: swapchain.inner.clone(),
                    index,
                }),
                extent: image::Extent {
                    width: pixel_width as _,
                    height: pixel_height as _,
                    depth: 1,
                },
                num_layers: None,
                format_desc,
                shader_channel: Channel::Float,
                mtl_format,
                mtl_type: metal::MTLTextureType::D2,
            })
            .collect();

        (swapchain, Backbuffer::Images(images))
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> Result<hal::FrameImage, ()> {
        unsafe {
            match sync {
                hal::FrameSync::Semaphore(semaphore) => {
                    // FIXME: this is definitely wrong
                    native::dispatch_semaphore_signal(semaphore.0);
                },
                hal::FrameSync::Fence(_fence) => unimplemented!(),
            }
        }

        let mut inner = self.inner.write().unwrap();
        let index = inner.frames
            .iter_mut()
            .position(|d| d.is_none())
            .expect("No frame available to acquire!");

        debug!("acquired frame {}", index);
        let layer = self.surface.render_layer.lock().unwrap();

        let _ap = AutoreleasePool::new(); // for the drawable
        inner.frames[index] = Some(unsafe {
            let drawable: *mut Object = msg_send![*layer, nextDrawable];
            assert!(!drawable.is_null());
            let texture: metal::Texture = msg_send![drawable, texture];
            msg_send![drawable, retain];
            msg_send![texture, retain];
            (drawable, texture)
        });

        Ok(index as _)
    }
}
<commit_msg>[mtl] hack persistent swapchain textures<commit_after>use {AutoreleasePool, Backend, QueueFamily};
use internal::Channel;
use native;
use device::{Device, PhysicalDevice};

use std::{fmt, ops};
use std::sync::{Arc, Mutex, RwLock};

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use metal;
use objc::runtime::{Object};
use core_graphics::base::CGFloat;
use core_graphics::geometry::CGRect;
use cocoa::foundation::{NSRect};
use foreign_types::{ForeignType, ForeignTypeRef};

pub type CAMetalLayer = *mut Object;
pub type CADrawable = *mut Object;

pub struct Surface {
    pub(crate) inner: Arc<SurfaceInner>,
    pub(crate) apply_pixel_scale: bool,
}

pub(crate) struct SurfaceInner {
    pub(crate) nsview: *mut Object,
    pub(crate) render_layer: Mutex<CAMetalLayer>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.nsview, release]; }
    }
}

#[derive(Debug)]
struct Frame {
    drawable: Option<CADrawable>,
    texture: metal::Texture,
}

pub struct SwapchainInner {
    frames: Vec<Frame>,
}

impl ops::Index<hal::FrameImage> for SwapchainInner {
    type Output = metal::TextureRef;
    fn index(&self, index: hal::FrameImage) -> &Self::Output {
        &self.frames[index as usize].texture
    }
}

unsafe impl Send for SwapchainInner {}
unsafe impl Sync for SwapchainInner {}

impl fmt::Debug for SwapchainInner {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Swapchain with {} image", self.frames.len())
    }
}

impl Drop for SwapchainInner {
    fn drop(&mut self) {
        for mut frame in self.frames.drain(..) {
            if let Some(drawable) = frame.drawable.take() {
                unsafe {
                    msg_send![drawable, release];
                }
            }
        }
    }
}

pub struct Swapchain {
    inner: Arc<RwLock<SwapchainInner>>,
    surface: Arc<SurfaceInner>,
    _size_pixels: (u64, u64),
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}

impl Swapchain {
    pub(crate) fn present(&self, index: hal::FrameImage) {
        let drawable = self.inner
            .write()
            .unwrap()
            .frames[index as usize]
            .drawable
            .take()
            .unwrap();
        unsafe {
            msg_send![drawable, present];
            //TODO: delay the actual release
            msg_send![drawable, release];
        }
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let (width, height) = self.pixel_dimensions();

        image::Kind::D2(width, height, 1, 1)
    }

    fn compatibility(
        &self, _: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>, Vec<hal::PresentMode>) {
        let render_layer_borrow = self.inner.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let max_frames: u64 = unsafe {
            msg_send![render_layer, maximumDrawableCount]
        };

        let caps = hal::SurfaceCapabilities {
            image_count: 2 .. max_frames as hal::FrameImage,
            current_extent: None,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
        };

        let formats = vec![
            format::Format::Bgra8Unorm,
            format::Format::Bgra8Srgb,
            format::Format::Rgba16Float,
        ];
        let present_modes = vec![
            hal::PresentMode::Fifo,
            hal::PresentMode::Immediate,
        ];

        (caps, Some(formats), present_modes)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true // TODO: Not sure this is the case, don't know associativity of IOSurface
    }
}

impl Surface {
    fn pixel_dimensions(&self) -> (image::Size, image::Size) {
        unsafe {
            // NSView bounds are measured in DIPs
            let bounds: NSRect = msg_send![self.inner.nsview, bounds];
            let bounds_pixel: NSRect = msg_send![self.inner.nsview, convertRectToBacking:bounds];
            (bounds_pixel.size.width as _, bounds_pixel.size.height as _)
        }
    }
}

impl Device {
    pub(crate) fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        let _ap = AutoreleasePool::new(); // for the drawable

        let mtl_format = self.private_caps
            .map_format(config.color_format)
            .expect("unsupported backbuffer format");

        let render_layer_borrow = surface.inner.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let nsview = surface.inner.nsview;
        let format_desc = config.color_format.surface_desc();
        let framebuffer_only = config.image_usage == image::Usage::COLOR_ATTACHMENT;
        let display_sync = match config.present_mode {
            hal::PresentMode::Immediate => false,
            _ => true,
        };
        let device = self.shared.device.lock().unwrap();
        let device_raw: &metal::DeviceRef = &*device;

        let (view_size, scale_factor) = unsafe {
            msg_send![render_layer, setDevice: device_raw];
            msg_send![render_layer, setPixelFormat: mtl_format];
            msg_send![render_layer, setFramebufferOnly: framebuffer_only];
            msg_send![render_layer, setMaximumDrawableCount: config.image_count as u64];
            //TODO: only set it where supported
            msg_send![render_layer, setDisplaySyncEnabled: display_sync];
            //msg_send![render_layer, setPresentsWithTransaction: true];

            // Update render layer size
            let view_points_size: CGRect = msg_send![nsview, bounds];
            msg_send![render_layer, setBounds: view_points_size];

            let view_window: *mut Object = msg_send![nsview, window];
            if view_window.is_null() {
                panic!("surface is not attached to a window");
            }
            let scale_factor: CGFloat = if surface.apply_pixel_scale {
                msg_send![view_window, backingScaleFactor]
            } else {
                1.0
            };
            msg_send![render_layer, setContentsScale: scale_factor];
            info!("view points size {:?} scale factor {:?}", view_points_size, scale_factor);
            (view_points_size.size, scale_factor)
        };

        let pixel_width = (view_size.width * scale_factor) as u64;
        let pixel_height = (view_size.height * scale_factor) as u64;

        let inner = SwapchainInner {
            frames: (0 .. config.image_count)
                .map(|_| unsafe {
                    let drawable: *mut Object = msg_send![render_layer, nextDrawable];
                    assert!(!drawable.is_null());
                    let texture: metal::Texture = msg_send![drawable, texture];
                    //HACK: not retaining the texture here
                    Frame {
                        drawable: None, //Note: careful!
                        texture,
                    }
                })
                .collect(),
        };

        let swapchain = Swapchain {
            inner: Arc::new(RwLock::new(inner)),
            surface: surface.inner.clone(),
            _size_pixels: (pixel_width, pixel_height),
        };

        let images = (0 .. config.image_count)
            .map(|index| native::Image {
                root: native::ImageRoot::Frame(native::Frame {
                    swapchain: swapchain.inner.clone(),
                    index,
                }),
                extent: image::Extent {
                    width: pixel_width as _,
                    height: pixel_height as _,
                    depth: 1,
                },
                num_layers: None,
                format_desc,
                shader_channel: Channel::Float,
                mtl_format,
                mtl_type: metal::MTLTextureType::D2,
            })
            .collect();

        (swapchain, Backbuffer::Images(images))
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> Result<hal::FrameImage, ()> {
        let _ap = AutoreleasePool::new(); // for the drawable

        unsafe {
            match sync {
                hal::FrameSync::Semaphore(semaphore) => {
                    // FIXME: this is definitely wrong
                    native::dispatch_semaphore_signal(semaphore.0);
                },
                hal::FrameSync::Fence(_fence) => unimplemented!(),
            }
        }

        let layer_ref = self.surface.render_layer.lock().unwrap();
        let drawable: CADrawable = unsafe {
            msg_send![*layer_ref, nextDrawable]
        };
        let texture_temp: &metal::TextureRef = unsafe {
            msg_send![drawable, retain];
            msg_send![drawable, texture]
        };
        let mut inner = self.inner.write().unwrap();
        let index = inner.frames
            .iter()
            .position(|f| f.texture.as_ptr() == texture_temp.as_ptr())
            .expect(&format!("Surface lost? ptr {:?}, frames {:?}", texture_temp, inner.frames));
        inner.frames[index].drawable = Some(drawable);

        Ok(index as _)
    }
}
<|endoftext|>


<commit_before>extern crate "pkg-config" as pkg_config;

use std::os;
use std::io::{mod, fs, Command};
use std::io::process::InheritFd;

fn main() {
    let mut opts = pkg_config::default_options("libgit2");
    opts.atleast_version = Some("0.21.0".to_string());
    match pkg_config::find_library_opts("libgit2", &opts) {
        Ok(()) => return,
        Err(..) => {}
    }

    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = os::getenv("CFLAGS").unwrap_or(String::new());
    let target = os::getenv("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.as_slice().contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let _ = fs::mkdir(&dst.join("build"), io::USER_DIR);

    let mut cmd = Command::new("cmake");
    cmd.arg(src.join("libgit2"))
       .cwd(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg("-DCMAKE_BUILD_TYPE=Release")
           .arg(format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(format!("-DCMAKE_C_FLAGS={}", cflags)));
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .cwd(&dst.join("build")));

    println!("cargo:rustc-flags=-L {} -l git2:static",
             dst.join("lib").display());
    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32");
    } else if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn register_dep(dep: &str) {
    match os::getenv(format!("DEP_{}_ROOT", dep).as_slice()) {
        Some(s) => {
            let prefix = os::getenv("CMAKE_PREFIX_PATH").unwrap_or(String::new());
            let mut v = os::split_paths(prefix.as_slice());
            v.push(Path::new(s));
            os::setenv("CMAKE_PREFIX_PATH", os::join_paths(v.as_slice()).unwrap());
        }
        None => {}
    }
}
<commit_msg>Choose cmake profile based on cargo profile<commit_after>extern crate "pkg-config" as pkg_config;

use std::os;
use std::io::{mod, fs, Command};
use std::io::process::InheritFd;

fn main() {
    let mut opts = pkg_config::default_options("libgit2");
    opts.atleast_version = Some("0.21.0".to_string());
    match pkg_config::find_library_opts("libgit2", &opts) {
        Ok(()) => return,
        Err(..) => {}
    }

    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = os::getenv("CFLAGS").unwrap_or(String::new());
    let target = os::getenv("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.as_slice().contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let _ = fs::mkdir(&dst.join("build"), io::USER_DIR);

    let mut cmd = Command::new("cmake");
    cmd.arg(src.join("libgit2"))
       .cwd(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match os::getenv("PROFILE").unwrap().as_slice() {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(format!("-DCMAKE_C_FLAGS={}", cflags)));
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .cwd(&dst.join("build")));

    println!("cargo:rustc-flags=-L {} -l git2:static",
             dst.join("lib").display());
    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32");
    } else if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn register_dep(dep: &str) {
    match os::getenv(format!("DEP_{}_ROOT", dep).as_slice()) {
        Some(s) => {
            let prefix = os::getenv("CMAKE_PREFIX_PATH").unwrap_or(String::new());
            let mut v = os::split_paths(prefix.as_slice());
            v.push(Path::new(s));
            os::setenv("CMAKE_PREFIX_PATH", os::join_paths(v.as_slice()).unwrap());
        }
        None => {}
    }
}
<|endoftext|>


<commit_before>use conn::Conn;
use conn::futures::query_result::*;
use conn::futures::query_result::futures::CollectAll;
use conn::stmt::InnerStmt;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Future;
use lib_futures::Poll;
use proto::Column;
use proto::OkPacket;
use std::mem;
use std::sync::Arc;

enum Step {
    CollectText(CollectAll<TextQueryResult>),
    CollectBin(CollectAll<BinQueryResult>),
    Done(Conn),
    Consumed,
}

enum Out {
    Done(Conn),
}

pub struct DropResult {
    step: Step,
}

pub fn new(conn: Conn,
           has_result: Option<(Arc<Vec<Column>>, Option<OkPacket>, Option<InnerStmt>)>) -> DropResult
{
    let step;
    if let Some((cols, ok_packet, inner_stmt)) = has_result {
        if let Some(inner_stmt) = inner_stmt {
            let raw_result = new_raw::<BinaryResult, _>(conn, cols, ok_packet, Some(inner_stmt));
            step = Step::CollectBin(BinQueryResult::from(raw_result).collect_all());
        } else {
            let raw_result = new_raw::<TextResult, _>(conn, cols, ok_packet, None);
            step = Step::CollectText(TextQueryResult::from(raw_result).collect_all());
        }
    } else {
        step = Step::Done(conn);
    }
    DropResult {
        step: step,
    }
}

impl DropResult {
    fn either_poll(&mut self) -> Result<Async<Out>> {
        match self.step {
            Step::CollectText(ref mut fut) => {
                let (_, conn) = try_ready!(fut.poll());
                Ok(Ready(Out::Done(conn)))
            },
            Step::CollectBin(ref mut fut) => {
                let (_, stmt) = try_ready!(<CollectAll<BinQueryResult> as Future>::poll(fut));
                Ok(Ready(Out::Done(stmt.unwrap())))
            },
            Step::Done(_) => {
                if let Step::Done(conn) = mem::replace(&mut self.step, Step::Consumed) {
                    Ok(Ready(Out::Done(conn)))
                } else {
                    unreachable!()
                }
            },
            Step::Consumed => panic!("DropResult polled twice"),
        }
    }
}

impl Future for DropResult {
    type Item = Conn;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.either_poll()) {
            Out::Done(conn) => {
                self.step = Step::Consumed;
                Ok(Ready(conn))
            },
        }
    }
}
<commit_msg>Use UncollectedQueryResult::drop_result in Conn::drop_result<commit_after>use conn::Conn;
use conn::futures::query_result::*;
use conn::futures::query_result::futures::DropResult as DropQueryResult;
use conn::stmt::InnerStmt;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Future;
use lib_futures::Poll;
use lib_futures::Done;
use lib_futures::done;
use proto::Column;
use proto::OkPacket;
use std::sync::Arc;

steps! {
    DropResult {
        DropTextResult(DropQueryResult<TextQueryResult>),
        DropBinResult(DropQueryResult<BinQueryResult>),
        Done(Done<Conn, Error>),
    }
}

pub struct DropResult {
    step: Step,
}

pub fn new(conn: Conn,
           has_result: Option<(Arc<Vec<Column>>, Option<OkPacket>, Option<InnerStmt>)>) -> DropResult
{
    let step = if let Some((cols, ok_packet, inner_stmt)) = has_result {
        if let Some(inner_stmt) = inner_stmt {
            let raw_result = new_raw::<BinaryResult, _>(conn, cols, ok_packet, Some(inner_stmt));
            Step::DropBinResult(BinQueryResult::from(raw_result).drop_result())
        } else {
            let raw_result = new_raw::<TextResult, _>(conn, cols, ok_packet, None);
            Step::DropTextResult(TextQueryResult::from(raw_result).drop_result())
        }
    } else {
        Step::Done(done(Ok(conn)))
    };
    DropResult {
        step: step,
    }
}

impl Future for DropResult {
    type Item = Conn;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.either_poll()) {
            Out::DropTextResult(conn) => Ok(Ready(conn)),
            Out::DropBinResult(stmt) => Ok(Ready(stmt.unwrap())),
            Out::Done(conn) => Ok(Ready(conn)),
        }
    }
}
<|endoftext|>


<commit_before>use palette::{FromColor, Hsl, IntoColor, Lch, Pixel, Saturate, Srgb};

use image::{GenericImage, GenericImageView};

fn main() {
    let mut image = image::open("example-data/input/cat.png")
        .expect("could not open 'example-data/input/cat.png'")
        .to_rgb8();

    let width = image.width();
    let height = image.height();

    //Increase the saturation by 80% (!) as HSL in the left half, and as LCh
    //in the right half. Notice the strong yellow tone in the HSL part.
    {
        let mut sub_image = image.sub_image(0, 0, width / 2, height);
        let (width, height) = sub_image.dimensions();
        for x in 0..width {
            for y in 0..height {
                let color: Hsl = Srgb::from_raw(&sub_image.get_pixel(x, y).0)
                    .into_format()
                    .into_color();

                let saturated = color.saturate(0.8);
                sub_image.put_pixel(
                    x,
                    y,
                    image::Rgb(Srgb::from_color(saturated).into_format().into_raw()),
                );
            }
        }
    }

    {
        let mut sub_image = image.sub_image(width / 2, 0, width / 2, height);
        let (width, height) = sub_image.dimensions();
        for x in 0..width {
            for y in 0..height {
                let color: Lch = Srgb::from_raw(&sub_image.get_pixel(x, y).0)
                    .into_format()
                    .into_color();

                let saturated = color.saturate(0.8);
                sub_image.put_pixel(
                    x,
                    y,
                    image::Rgb(Srgb::from_color(saturated).into_format().into_raw()),
                );
            }
        }
    }

    let _ = std::fs::create_dir("example-data/output");
    match image.save("example-data/output/saturate.png") {
        Ok(()) => println!("see 'example-data/output/saturate.png' for the result"),
        Err(e) => println!("failed to write 'example-data/output/saturate.png': {}", e),
    }
}
<commit_msg>Tweak the numbers in the saturation example file<commit_after>use palette::{FromColor, Hsl, IntoColor, Lch, Pixel, Saturate, Srgb};

use image::{GenericImage, GenericImageView};

fn main() {
    let mut image = image::open("example-data/input/cat.png")
        .expect("could not open 'example-data/input/cat.png'")
        .to_rgb8();

    let width = image.width();
    let height = image.height();

    //Increase the saturation by 30% towards full saturation as HSL in the left half, and as LCh
    //in the right half. Notice the strong yellow tone in the HSL part.
    {
        let mut sub_image = image.sub_image(0, 0, width / 2, height);
        let (width, height) = sub_image.dimensions();
        for x in 0..width {
            for y in 0..height {
                let color: Hsl = Srgb::from_raw(&sub_image.get_pixel(x, y).0)
                    .into_format()
                    .into_color();

                let saturated = color.saturate(0.3);
                sub_image.put_pixel(
                    x,
                    y,
                    image::Rgb(Srgb::from_color(saturated).into_format().into_raw()),
                );
            }
        }
    }

    {
        let mut sub_image = image.sub_image(width / 2, 0, width / 2, height);
        let (width, height) = sub_image.dimensions();
        for x in 0..width {
            for y in 0..height {
                let color: Lch = Srgb::from_raw(&sub_image.get_pixel(x, y).0)
                    .into_format()
                    .into_color();

                let saturated = color.saturate(0.3);
                sub_image.put_pixel(
                    x,
                    y,
                    image::Rgb(Srgb::from_color(saturated).into_format().into_raw()),
                );
            }
        }
    }

    let _ = std::fs::create_dir("example-data/output");
    match image.save("example-data/output/saturate.png") {
        Ok(()) => println!("see 'example-data/output/saturate.png' for the result"),
        Err(e) => println!("failed to write 'example-data/output/saturate.png': {}", e),
    }
}
<|endoftext|>