<commit_before>use super::*;

use syntax_pos::DUMMY_SP;
use syntax::ast::*;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax::with_default_globals;

fn word_cfg(s: &str) -> Cfg {
    Cfg::Cfg(Symbol::intern(s), None)
}

fn name_value_cfg(name: &str, value: &str) -> Cfg {
    Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
}

fn dummy_meta_item_word(name: &str) -> MetaItem {
    MetaItem {
        path: Path::from_ident(Ident::from_str(name)),
        kind: MetaItemKind::Word,
        span: DUMMY_SP,
    }
}

macro_rules! dummy_meta_item_list {
    ($name:ident, [$($list:ident),* $(,)?]) => {
        MetaItem {
            path: Path::from_ident(Ident::from_str(stringify!($name))),
            kind: MetaItemKind::List(vec![
                $(
                    NestedMetaItem::MetaItem(
                        dummy_meta_item_word(stringify!($list)),
                    ),
                )*
            ]),
            span: DUMMY_SP,
        }
    };

    ($name:ident, [$($list:expr),* $(,)?]) => {
        MetaItem {
            path: Path::from_ident(Ident::from_str(stringify!($name))),
            node: MetaItemKind::List(vec![
                $(
                    NestedMetaItem::MetaItem($list),
                )*
            ]),
            span: DUMMY_SP,
        }
    };
}

#[test]
fn test_cfg_not() {
    with_default_globals(|| {
        assert_eq!(!Cfg::False, Cfg::True);
        assert_eq!(!Cfg::True, Cfg::False);
        assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test"))));
        assert_eq!(
            !Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
            Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")])))
        );
        assert_eq!(
            !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
            Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")])))
        );
        assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test"));
    })
}

#[test]
fn test_cfg_and() {
    with_default_globals(|| {
        let mut x = Cfg::False;
        x &= Cfg::True;
        assert_eq!(x, Cfg::False);

        x = word_cfg("test");
        x &= Cfg::False;
        assert_eq!(x, Cfg::False);

        x = word_cfg("test2");
        x &= Cfg::True;
        assert_eq!(x, word_cfg("test2"));

        x = Cfg::True;
        x &= word_cfg("test3");
        assert_eq!(x, word_cfg("test3"));

        x &= word_cfg("test4");
        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));

        x &= word_cfg("test5");
        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));

        x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
        assert_eq!(x, Cfg::All(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
        ]));

        let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
        y &= x;
        assert_eq!(y, Cfg::All(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
            Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
        ]));

        assert_eq!(
            word_cfg("a") & word_cfg("b") & word_cfg("c"),
            Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
        );
    })
}

#[test]
fn test_cfg_or() {
    with_default_globals(|| {
        let mut x = Cfg::True;
        x |= Cfg::False;
        assert_eq!(x, Cfg::True);

        x = word_cfg("test");
        x |= Cfg::True;
        assert_eq!(x, Cfg::True);

        x = word_cfg("test2");
        x |= Cfg::False;
        assert_eq!(x, word_cfg("test2"));

        x = Cfg::False;
        x |= word_cfg("test3");
        assert_eq!(x, word_cfg("test3"));

        x |= word_cfg("test4");
        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));

        x |= word_cfg("test5");
        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));

        x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
        assert_eq!(x, Cfg::Any(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
        ]));

        let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
        y |= x;
        assert_eq!(y, Cfg::Any(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
            Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
        ]));

        assert_eq!(
            word_cfg("a") | word_cfg("b") | word_cfg("c"),
            Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
        );
    })
}

#[test]
fn test_parse_ok() {
    with_default_globals(|| {
        let mi = dummy_meta_item_word("all");
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));

        let mi = attr::mk_name_value_item_str(
            Ident::from_str("all"),
            Symbol::intern("done"),
            DUMMY_SP,
        );
        assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));

        let mi = dummy_meta_item_list!(all, [a, b]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));

        let mi = dummy_meta_item_list!(any, [a, b]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));

        let mi = dummy_meta_item_list!(not, [a]);
        assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));

        let mi = dummy_meta_item_list!(not, [
            dummy_meta_item_list!(any, [
                dummy_meta_item_word("a"),
                dummy_meta_item_list!(all, [b, c]),
            ]),
        ]);
        assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));

        let mi = dummy_meta_item_list!(all, [a, b, c]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
    })
}

#[test]
fn test_parse_err() {
    with_default_globals(|| {
        let mi = attr::mk_name_value_item(
            Ident::from_str("foo"),
            LitKind::Bool(false),
            DUMMY_SP,
        );
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, [a, b]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, []);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(foo, []);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(all, [
            dummy_meta_item_list!(foo, []),
            dummy_meta_item_word("b"),
        ]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(any, [
            dummy_meta_item_word("a"),
            dummy_meta_item_list!(foo, []),
        ]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, [
            dummy_meta_item_list!(foo, []),
        ]);
        assert!(Cfg::parse(&mi).is_err());
    })
}

#[test]
fn test_render_short_html() {
    with_default_globals(|| {
        assert_eq!(
            word_cfg("unix").render_short_html(),
            "Unix"
        );
        assert_eq!(
            name_value_cfg("target_os", "macos").render_short_html(),
            "macOS"
        );
        assert_eq!(
            name_value_cfg("target_pointer_width", "16").render_short_html(),
            "16-bit"
        );
        assert_eq!(
            name_value_cfg("target_endian", "little").render_short_html(),
            "Little-endian"
        );
        assert_eq!(
            (!word_cfg("windows")).render_short_html(),
            "Non-Windows"
        );
        assert_eq!(
            (word_cfg("unix") & word_cfg("windows")).render_short_html(),
            "Unix and Windows"
        );
        assert_eq!(
            (word_cfg("unix") | word_cfg("windows")).render_short_html(),
            "Unix or Windows"
        );
        assert_eq!(
            (
                word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
            ).render_short_html(),
            "Unix and Windows and debug-assertions enabled"
        );
        assert_eq!(
            (
                word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
            ).render_short_html(),
            "Unix or Windows or debug-assertions enabled"
        );
        assert_eq!(
            (
                !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
            ).render_short_html(),
            "Neither Unix nor Windows nor debug-assertions enabled"
        );
        assert_eq!(
            (
                (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
                (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
            ).render_short_html(),
            "Unix and x86-64, or Windows and 64-bit"
        );
        assert_eq!(
            (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(),
            "Not (Unix and Windows)"
        );
        assert_eq!(
            (
                (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
            ).render_short_html(),
            "(Debug-assertions enabled or Windows) and Unix"
        );
        assert_eq!(
            name_value_cfg("target_feature", "sse2").render_short_html(),
            "sse2"
        );
        assert_eq!(
            (
                name_value_cfg("target_arch", "x86_64") &
                name_value_cfg("target_feature", "sse2")
            ).render_short_html(),
            "x86-64 and sse2"
        );
    })
}

#[test]
fn test_render_long_html() {
    with_default_globals(|| {
        assert_eq!(
            word_cfg("unix").render_long_html(),
            "This is supported on Unix only."
        );
        assert_eq!(
            name_value_cfg("target_os", "macos").render_long_html(),
            "This is supported on macOS only."
        );
        assert_eq!(
            name_value_cfg("target_pointer_width", "16").render_long_html(),
            "This is supported on 16-bit only."
        );
        assert_eq!(
            name_value_cfg("target_endian", "little").render_long_html(),
            "This is supported on little-endian only."
        );
        assert_eq!(
            (!word_cfg("windows")).render_long_html(),
            "This is supported on non-Windows only."
        );
        assert_eq!(
            (word_cfg("unix") & word_cfg("windows")).render_long_html(),
            "This is supported on Unix and Windows only."
        );
        assert_eq!(
            (word_cfg("unix") | word_cfg("windows")).render_long_html(),
            "This is supported on Unix or Windows only."
        );
        assert_eq!(
            (
                word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
            ).render_long_html(),
            "This is supported on Unix and Windows and debug-assertions enabled\
                 only."
        );
        assert_eq!(
            (
                word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
            ).render_long_html(),
            "This is supported on Unix or Windows or debug-assertions enabled\
                 only."
        );
        assert_eq!(
            (
                !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
            ).render_long_html(),
            "This is supported on neither Unix nor Windows nor debug-assertions \
                enabled."
        );
        assert_eq!(
            (
                (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
                (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
            ).render_long_html(),
            "This is supported on Unix and x86-64, or Windows and 64-bit \
                only."
        );
        assert_eq!(
            (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(),
            "This is supported on not (Unix and Windows)."
        );
        assert_eq!(
            (
                (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
            ).render_long_html(),
            "This is supported on (debug-assertions enabled or Windows) and Unix\
             only."
        );
        assert_eq!(
            name_value_cfg("target_feature", "sse2").render_long_html(),
            "This is supported with target feature sse2 only."
        );
        assert_eq!(
            (
                name_value_cfg("target_arch", "x86_64") &
                name_value_cfg("target_feature", "sse2")
            ).render_long_html(),
            "This is supported on x86-64 and target feature \
            sse2 only."
        );
    })
}
<commit_msg>Fix librustcdoc test<commit_after>use super::*;

use syntax_pos::DUMMY_SP;
use syntax::ast::*;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax::with_default_globals;

fn word_cfg(s: &str) -> Cfg {
    Cfg::Cfg(Symbol::intern(s), None)
}

fn name_value_cfg(name: &str, value: &str) -> Cfg {
    Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
}

fn dummy_meta_item_word(name: &str) -> MetaItem {
    MetaItem {
        path: Path::from_ident(Ident::from_str(name)),
        kind: MetaItemKind::Word,
        span: DUMMY_SP,
    }
}

macro_rules! dummy_meta_item_list {
    ($name:ident, [$($list:ident),* $(,)?]) => {
        MetaItem {
            path: Path::from_ident(Ident::from_str(stringify!($name))),
            kind: MetaItemKind::List(vec![
                $(
                    NestedMetaItem::MetaItem(
                        dummy_meta_item_word(stringify!($list)),
                    ),
                )*
            ]),
            span: DUMMY_SP,
        }
    };

    ($name:ident, [$($list:expr),* $(,)?]) => {
        MetaItem {
            path: Path::from_ident(Ident::from_str(stringify!($name))),
            kind: MetaItemKind::List(vec![
                $(
                    NestedMetaItem::MetaItem($list),
                )*
            ]),
            span: DUMMY_SP,
        }
    };
}

#[test]
fn test_cfg_not() {
    with_default_globals(|| {
        assert_eq!(!Cfg::False, Cfg::True);
        assert_eq!(!Cfg::True, Cfg::False);
        assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test"))));
        assert_eq!(
            !Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
            Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")])))
        );
        assert_eq!(
            !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
            Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")])))
        );
        assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test"));
    })
}

#[test]
fn test_cfg_and() {
    with_default_globals(|| {
        let mut x = Cfg::False;
        x &= Cfg::True;
        assert_eq!(x, Cfg::False);

        x = word_cfg("test");
        x &= Cfg::False;
        assert_eq!(x, Cfg::False);

        x = word_cfg("test2");
        x &= Cfg::True;
        assert_eq!(x, word_cfg("test2"));

        x = Cfg::True;
        x &= word_cfg("test3");
        assert_eq!(x, word_cfg("test3"));

        x &= word_cfg("test4");
        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));

        x &= word_cfg("test5");
        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));

        x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
        assert_eq!(x, Cfg::All(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
        ]));

        let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
        y &= x;
        assert_eq!(y, Cfg::All(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
            Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
        ]));

        assert_eq!(
            word_cfg("a") & word_cfg("b") & word_cfg("c"),
            Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
        );
    })
}

#[test]
fn test_cfg_or() {
    with_default_globals(|| {
        let mut x = Cfg::True;
        x |= Cfg::False;
        assert_eq!(x, Cfg::True);

        x = word_cfg("test");
        x |= Cfg::True;
        assert_eq!(x, Cfg::True);

        x = word_cfg("test2");
        x |= Cfg::False;
        assert_eq!(x, word_cfg("test2"));

        x = Cfg::False;
        x |= word_cfg("test3");
        assert_eq!(x, word_cfg("test3"));

        x |= word_cfg("test4");
        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));

        x |= word_cfg("test5");
        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));

        x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
        assert_eq!(x, Cfg::Any(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
        ]));

        let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
        y |= x;
        assert_eq!(y, Cfg::Any(vec![
            word_cfg("test3"),
            word_cfg("test4"),
            word_cfg("test5"),
            word_cfg("test6"),
            word_cfg("test7"),
            Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
        ]));

        assert_eq!(
            word_cfg("a") | word_cfg("b") | word_cfg("c"),
            Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
        );
    })
}

#[test]
fn test_parse_ok() {
    with_default_globals(|| {
        let mi = dummy_meta_item_word("all");
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));

        let mi = attr::mk_name_value_item_str(
            Ident::from_str("all"),
            Symbol::intern("done"),
            DUMMY_SP,
        );
        assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));

        let mi = dummy_meta_item_list!(all, [a, b]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));

        let mi = dummy_meta_item_list!(any, [a, b]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));

        let mi = dummy_meta_item_list!(not, [a]);
        assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));

        let mi = dummy_meta_item_list!(not, [
            dummy_meta_item_list!(any, [
                dummy_meta_item_word("a"),
                dummy_meta_item_list!(all, [b, c]),
            ]),
        ]);
        assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));

        let mi = dummy_meta_item_list!(all, [a, b, c]);
        assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
    })
}

#[test]
fn test_parse_err() {
    with_default_globals(|| {
        let mi = attr::mk_name_value_item(
            Ident::from_str("foo"),
            LitKind::Bool(false),
            DUMMY_SP,
        );
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, [a, b]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, []);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(foo, []);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(all, [
            dummy_meta_item_list!(foo, []),
            dummy_meta_item_word("b"),
        ]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(any, [
            dummy_meta_item_word("a"),
            dummy_meta_item_list!(foo, []),
        ]);
        assert!(Cfg::parse(&mi).is_err());

        let mi = dummy_meta_item_list!(not, [
            dummy_meta_item_list!(foo, []),
        ]);
        assert!(Cfg::parse(&mi).is_err());
    })
}

#[test]
fn test_render_short_html() {
    with_default_globals(|| {
        assert_eq!(
            word_cfg("unix").render_short_html(),
            "Unix"
        );
        assert_eq!(
            name_value_cfg("target_os", "macos").render_short_html(),
            "macOS"
        );
        assert_eq!(
            name_value_cfg("target_pointer_width", "16").render_short_html(),
            "16-bit"
        );
        assert_eq!(
            name_value_cfg("target_endian", "little").render_short_html(),
            "Little-endian"
        );
        assert_eq!(
            (!word_cfg("windows")).render_short_html(),
            "Non-Windows"
        );
        assert_eq!(
            (word_cfg("unix") & word_cfg("windows")).render_short_html(),
            "Unix and Windows"
        );
        assert_eq!(
            (word_cfg("unix") | word_cfg("windows")).render_short_html(),
            "Unix or Windows"
        );
        assert_eq!(
            (
                word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
            ).render_short_html(),
            "Unix and Windows and debug-assertions enabled"
        );
        assert_eq!(
            (
                word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
            ).render_short_html(),
            "Unix or Windows or debug-assertions enabled"
        );
        assert_eq!(
            (
                !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
            ).render_short_html(),
            "Neither Unix nor Windows nor debug-assertions enabled"
        );
        assert_eq!(
            (
                (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
                (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
            ).render_short_html(),
            "Unix and x86-64, or Windows and 64-bit"
        );
        assert_eq!(
            (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(),
            "Not (Unix and Windows)"
        );
        assert_eq!(
            (
                (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
            ).render_short_html(),
            "(Debug-assertions enabled or Windows) and Unix"
        );
        assert_eq!(
            name_value_cfg("target_feature", "sse2").render_short_html(),
            "sse2"
        );
        assert_eq!(
            (
                name_value_cfg("target_arch", "x86_64") &
                name_value_cfg("target_feature", "sse2")
            ).render_short_html(),
            "x86-64 and sse2"
        );
    })
}

#[test]
fn test_render_long_html() {
    with_default_globals(|| {
        assert_eq!(
            word_cfg("unix").render_long_html(),
            "This is supported on Unix only."
        );
        assert_eq!(
            name_value_cfg("target_os", "macos").render_long_html(),
            "This is supported on macOS only."
        );
        assert_eq!(
            name_value_cfg("target_pointer_width", "16").render_long_html(),
            "This is supported on 16-bit only."
        );
        assert_eq!(
            name_value_cfg("target_endian", "little").render_long_html(),
            "This is supported on little-endian only."
        );
        assert_eq!(
            (!word_cfg("windows")).render_long_html(),
            "This is supported on non-Windows only."
        );
        assert_eq!(
            (word_cfg("unix") & word_cfg("windows")).render_long_html(),
            "This is supported on Unix and Windows only."
        );
        assert_eq!(
            (word_cfg("unix") | word_cfg("windows")).render_long_html(),
            "This is supported on Unix or Windows only."
        );
        assert_eq!(
            (
                word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
            ).render_long_html(),
            "This is supported on Unix and Windows and debug-assertions enabled\
                 only."
        );
        assert_eq!(
            (
                word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
            ).render_long_html(),
            "This is supported on Unix or Windows or debug-assertions enabled\
                 only."
        );
        assert_eq!(
            (
                !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
            ).render_long_html(),
            "This is supported on neither Unix nor Windows nor debug-assertions \
                enabled."
        );
        assert_eq!(
            (
                (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
                (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
            ).render_long_html(),
            "This is supported on Unix and x86-64, or Windows and 64-bit \
                only."
        );
        assert_eq!(
            (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(),
            "This is supported on not (Unix and Windows)."
        );
        assert_eq!(
            (
                (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
            ).render_long_html(),
            "This is supported on (debug-assertions enabled or Windows) and Unix\
             only."
        );
        assert_eq!(
            name_value_cfg("target_feature", "sse2").render_long_html(),
            "This is supported with target feature sse2 only."
        );
        assert_eq!(
            (
                name_value_cfg("target_arch", "x86_64") &
                name_value_cfg("target_feature", "sse2")
            ).render_long_html(),
            "This is supported on x86-64 and target feature \
            sse2 only."
        );
    })
}
<|endoftext|>


<commit_before>//! Mocks for testing

pub mod clitools;
pub mod dist;

use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::sync::Arc;

// Mock of the on-disk structure of rust-installer installers
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockInstallerBuilder {
    pub components: Vec<MockComponentBuilder>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockComponentBuilder {
    pub name: String,
    pub files: Vec<MockFile>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockFile {
    path: String,
    contents: Contents,
}

#[derive(PartialEq, Eq, Hash, Clone)]
enum Contents {
    File(MockContents),
    Dir(Vec<(&'static str, MockContents)>),
}

#[derive(PartialEq, Eq, Hash, Clone)]
struct MockContents {
    contents: Arc<Vec<u8>>,
    executable: bool,
}

impl MockInstallerBuilder {
    pub fn build(&self, path: &Path) {
        for component in &self.components {
            // Update the components file
            let comp_file = path.join("components");
            let mut comp_file = OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(comp_file.clone())
                .unwrap();
            writeln!(comp_file, "{}", component.name).unwrap();

            // Create the component directory
            let component_dir = path.join(&component.name);
            if !component_dir.exists() {
                fs::create_dir(&component_dir).unwrap();
            }

            // Create the component files and manifest
            let mut manifest = File::create(component_dir.join("manifest.in")).unwrap();
            for file in component.files.iter() {
                match file.contents {
                    Contents::Dir(_) => {
                        writeln!(manifest, "dir:{}", file.path).unwrap();
                    }
                    Contents::File(_) => {
                        writeln!(manifest, "file:{}", file.path).unwrap();
                    }
                }
                file.build(&component_dir);
            }
        }

        let mut ver = File::create(path.join("rust-installer-version")).unwrap();
        writeln!(ver, "3").unwrap();
    }
}

impl MockFile {
    pub fn new<S: Into<String>>(path: S, contents: &[u8]) -> MockFile {
        MockFile::_new(path.into(), Arc::new(contents.to_vec()))
    }

    pub fn new_arc<S: Into<String>>(path: S, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile::_new(path.into(), contents)
    }

    fn _new(path: String, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile {
            path,
            contents: Contents::File(MockContents {
                contents,
                executable: false,
            }),
        }
    }

    pub fn new_dir(path: &str, files: &[(&'static str, &'static [u8], bool)]) -> MockFile {
        MockFile {
            path: path.to_string(),
            contents: Contents::Dir(
                files
                    .iter()
                    .map(|&(name, data, exe)| {
                        (
                            name,
                            MockContents {
                                contents: Arc::new(data.to_vec()),
                                executable: exe,
                            },
                        )
                    })
                    .collect(),
            ),
        }
    }

    pub fn executable(mut self, exe: bool) -> Self {
        match self.contents {
            Contents::File(ref mut c) => c.executable = exe,
            _ => {}
        }
        self
    }

    pub fn build(&self, path: &Path) {
        let path = path.join(&self.path);
        match self.contents {
            Contents::Dir(ref files) => {
                for &(ref name, ref contents) in files {
                    let fname = path.join(name);
                    contents.build(&fname);
                }
            }
            Contents::File(ref contents) => contents.build(&path),
        }
    }
}

impl MockContents {
    fn build(&self, path: &Path) {
        let dir_path = path.parent().unwrap().to_owned();
        fs::create_dir_all(dir_path).unwrap();
        File::create(&path)
            .unwrap()
            .write_all(&self.contents)
            .unwrap();

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            if self.executable {
                let mut perm = fs::metadata(path).unwrap().permissions();
                perm.set_mode(0o755);
                fs::set_permissions(path, perm).unwrap();
            }
        }
    }
}

#[cfg(windows)]
pub fn get_path() -> Option<String> {
    use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::RegKey;

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    environment.get_value("PATH").ok()
}

#[cfg(windows)]
pub fn restore_path(p: Option<String>) {
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::{RegKey, RegValue};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    if let Some(p) = p.as_ref() {
        let reg_value = RegValue {
            bytes: string_to_winreg_bytes(&p),
            vtype: RegType::REG_EXPAND_SZ,
        };
        environment.set_raw_value("PATH", &reg_value).unwrap();
    } else {
        let _ = environment.delete_value("PATH");
    }

    fn string_to_winreg_bytes(s: &str) -> Vec<u8> {
        use std::ffi::OsString;
        use std::os::windows::ffi::OsStrExt;
        let v: Vec<_> = OsString::from(format!("{}\x00", s)).encode_wide().collect();
        unsafe { ::std::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() }
    }
}

#[cfg(unix)]
pub fn get_path() -> Option<String> {
    None
}

#[cfg(unix)]
pub fn restore_path(_: Option<String>) {}
<commit_msg>clippy: Fix single_match<commit_after>//! Mocks for testing

pub mod clitools;
pub mod dist;

use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::sync::Arc;

// Mock of the on-disk structure of rust-installer installers
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockInstallerBuilder {
    pub components: Vec<MockComponentBuilder>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockComponentBuilder {
    pub name: String,
    pub files: Vec<MockFile>,
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct MockFile {
    path: String,
    contents: Contents,
}

#[derive(PartialEq, Eq, Hash, Clone)]
enum Contents {
    File(MockContents),
    Dir(Vec<(&'static str, MockContents)>),
}

#[derive(PartialEq, Eq, Hash, Clone)]
struct MockContents {
    contents: Arc<Vec<u8>>,
    executable: bool,
}

impl MockInstallerBuilder {
    pub fn build(&self, path: &Path) {
        for component in &self.components {
            // Update the components file
            let comp_file = path.join("components");
            let mut comp_file = OpenOptions::new()
                .write(true)
                .append(true)
                .create(true)
                .open(comp_file.clone())
                .unwrap();
            writeln!(comp_file, "{}", component.name).unwrap();

            // Create the component directory
            let component_dir = path.join(&component.name);
            if !component_dir.exists() {
                fs::create_dir(&component_dir).unwrap();
            }

            // Create the component files and manifest
            let mut manifest = File::create(component_dir.join("manifest.in")).unwrap();
            for file in component.files.iter() {
                match file.contents {
                    Contents::Dir(_) => {
                        writeln!(manifest, "dir:{}", file.path).unwrap();
                    }
                    Contents::File(_) => {
                        writeln!(manifest, "file:{}", file.path).unwrap();
                    }
                }
                file.build(&component_dir);
            }
        }

        let mut ver = File::create(path.join("rust-installer-version")).unwrap();
        writeln!(ver, "3").unwrap();
    }
}

impl MockFile {
    pub fn new<S: Into<String>>(path: S, contents: &[u8]) -> MockFile {
        MockFile::_new(path.into(), Arc::new(contents.to_vec()))
    }

    pub fn new_arc<S: Into<String>>(path: S, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile::_new(path.into(), contents)
    }

    fn _new(path: String, contents: Arc<Vec<u8>>) -> MockFile {
        MockFile {
            path,
            contents: Contents::File(MockContents {
                contents,
                executable: false,
            }),
        }
    }

    pub fn new_dir(path: &str, files: &[(&'static str, &'static [u8], bool)]) -> MockFile {
        MockFile {
            path: path.to_string(),
            contents: Contents::Dir(
                files
                    .iter()
                    .map(|&(name, data, exe)| {
                        (
                            name,
                            MockContents {
                                contents: Arc::new(data.to_vec()),
                                executable: exe,
                            },
                        )
                    })
                    .collect(),
            ),
        }
    }

    pub fn executable(mut self, exe: bool) -> Self {
        if let Contents::File(c) = &mut self.contents {
            c.executable = exe;
        }
        self
    }

    pub fn build(&self, path: &Path) {
        let path = path.join(&self.path);
        match self.contents {
            Contents::Dir(ref files) => {
                for &(ref name, ref contents) in files {
                    let fname = path.join(name);
                    contents.build(&fname);
                }
            }
            Contents::File(ref contents) => contents.build(&path),
        }
    }
}

impl MockContents {
    fn build(&self, path: &Path) {
        let dir_path = path.parent().unwrap().to_owned();
        fs::create_dir_all(dir_path).unwrap();
        File::create(&path)
            .unwrap()
            .write_all(&self.contents)
            .unwrap();

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            if self.executable {
                let mut perm = fs::metadata(path).unwrap().permissions();
                perm.set_mode(0o755);
                fs::set_permissions(path, perm).unwrap();
            }
        }
    }
}

#[cfg(windows)]
pub fn get_path() -> Option<String> {
    use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::RegKey;

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    environment.get_value("PATH").ok()
}

#[cfg(windows)]
pub fn restore_path(p: Option<String>) {
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
    use winreg::{RegKey, RegValue};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let environment = root
        .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
        .unwrap();

    if let Some(p) = p.as_ref() {
        let reg_value = RegValue {
            bytes: string_to_winreg_bytes(&p),
            vtype: RegType::REG_EXPAND_SZ,
        };
        environment.set_raw_value("PATH", &reg_value).unwrap();
    } else {
        let _ = environment.delete_value("PATH");
    }

    fn string_to_winreg_bytes(s: &str) -> Vec<u8> {
        use std::ffi::OsString;
        use std::os::windows::ffi::OsStrExt;
        let v: Vec<_> = OsString::from(format!("{}\x00", s)).encode_wide().collect();
        unsafe { ::std::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() }
    }
}

#[cfg(unix)]
pub fn get_path() -> Option<String> {
    None
}

#[cfg(unix)]
pub fn restore_path(_: Option<String>) {}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! libra_channel provides an mpsc channel which has two ends `libra_channel::Receiver`
//! and `libra_channel::Sender` similar to existing mpsc data structures.
//! What makes it different from existing mpsc channels is that we have full control
//! over how the internal queueing in the channel happens and how we schedule messages
//! to be sent out from this channel.
//! Internally, it uses the `PerKeyQueue` to store messages
use crate::message_queues::{PerKeyQueue, QueueStyle};
use anyhow::{ensure, Result};
use futures::{
    channel::oneshot,
    stream::{FusedStream, Stream},
};
use libra_metrics::IntCounterVec;
use std::{
    fmt::{Debug, Formatter},
    hash::Hash,
    num::NonZeroUsize,
    pin::Pin,
    sync::{Arc, Mutex},
    task::{Context, Poll, Waker},
};

/// SharedState is a data structure private to this module which is
/// shared by the sender and receiver.
#[derive(Debug)]
struct SharedState<K: Eq + Hash + Clone, M> {
    /// The internal queue of messages in this Channel
    internal_queue: PerKeyQueue<K, (M, Option<oneshot::Sender<ElementStatus<M>>>)>,
    /// Waker is needed so that the Sender can notify the task executor/scheduler
    /// that something has been pushed to the internal_queue and it ready for
    /// consumption by the Receiver and then the executor/scheduler will wake up
    /// the Receiver task to process the next item.
    waker: Option<Waker>,

    /// A boolean which tracks whether the receiver has dropped
    receiver_dropped: bool,
    /// A boolean which tracks whether the stream has terminated
    /// A stream is considered terminated when sender has dropped
    /// and we have drained everything inside our internal queue
    stream_terminated: bool,
}

/// The sending end of the libra_channel.
#[derive(Debug)]
pub struct Sender<K: Eq + Hash + Clone, M> {
    shared_state: Arc<Mutex<SharedState<K, M>>>,
}

/// The status of an element inserted into a libra_channel. If the element is successfully
/// dequeued, ElementStatus::Dequeued is sent to the sender. If it is dropped
/// ElementStatus::Dropped is sent to the sender along with the dropped element.
pub enum ElementStatus<M> {
    Dequeued,
    Dropped(M),
}

impl<M: PartialEq> PartialEq for ElementStatus<M> {
    fn eq(&self, other: &ElementStatus<M>) -> bool {
        match (self, other) {
            (ElementStatus::Dequeued, ElementStatus::Dequeued) => true,
            (ElementStatus::Dropped(a), ElementStatus::Dropped(b)) => a.eq(b),
            _ => false,
        }
    }
}

impl<M: Debug> Debug for ElementStatus<M> {
    fn fmt(&self, f: &mut Formatter) -> std::result::Result<(), std::fmt::Error> {
        match self {
            ElementStatus::Dequeued => write!(f, "Dequeued"),
            ElementStatus::Dropped(v) => write!(f, "Dropped({:?})", v),
        }
    }
}

impl<K: Eq + Hash + Clone, M> Sender<K, M> {
    /// This adds the message into the internal queue data structure. This is a
    /// synchronous call.
    pub fn push(&mut self, key: K, message: M) -> Result<()> {
        self.push_with_feedback(key, message, None)
    }

    /// Same as `push`, but this function also accepts a oneshot::Sender over which the sender can
    /// be notified when the message eventually gets delivered or dropped.
    pub fn push_with_feedback(
        &mut self,
        key: K,
        message: M,
        status_ch: Option<oneshot::Sender<ElementStatus<M>>>,
    ) -> Result<()> {
        let mut shared_state = self.shared_state.lock().unwrap();
        ensure!(!shared_state.receiver_dropped, "Channel is closed");
        let dropped = shared_state.internal_queue.push(key, (message, status_ch));
        // If this or an existing message had to be dropped because of the queue being full, we
        // notify the corresponding status channel if it was registered.
        if let Some((dropped_val, Some(dropped_status_ch))) = dropped {
            // Ignore errors.
            let _err = dropped_status_ch.send(ElementStatus::Dropped(dropped_val));
        }
        if let Some(w) = shared_state.waker.take() {
            w.wake();
        }
        Ok(())
    }
}

impl<K: Eq + Hash + Clone, M> Clone for Sender<K, M> {
    fn clone(&self) -> Self {
        Sender {
            shared_state: self.shared_state.clone(),
        }
    }
}

impl<K: Eq + Hash + Clone, M> Drop for Sender<K, M> {
    fn drop(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();
        if let Some(w) = shared_state.waker.take() {
            w.wake();
        }
    }
}

/// The receiving end of the libra_channel.
pub struct Receiver<K: Eq + Hash + Clone, M> {
    shared_state: Arc<Mutex<SharedState<K, M>>>,
}

impl<K: Eq + Hash + Clone, M> Receiver<K, M> {
    /// Removes all the previously sent transactions that have not been consumed yet and cleans up
    /// the internal queue structure (GC of the previous keys).
    pub fn clear(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();
        shared_state.internal_queue.clear();
    }
}

impl<K: Eq + Hash + Clone, M> Drop for Receiver<K, M> {
    fn drop(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();
        shared_state.receiver_dropped = true;
    }
}

impl<K: Eq + Hash + Clone, M> Stream for Receiver<K, M> {
    type Item = M;
    /// poll_next checks whether there is something ready for consumption from the internal
    /// queue. If there is, then it returns immediately. If the internal_queue is empty,
    /// it sets the waker passed to it by the scheduler/executor and returns Pending
    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut shared_state = self.shared_state.lock().unwrap();
        if let Some((val, status_ch)) = shared_state.internal_queue.pop() {
            if let Some(status_ch) = status_ch {
                let _err = status_ch.send(ElementStatus::Dequeued);
            }
            Poll::Ready(Some(val))
        // if the only Arc reference to `shared_state` is 1, which is this receiver,
        // this must mean all senders have been dropped (and so the stream is terminated)
        } else if Arc::strong_count(&self.shared_state) == 1 {
            shared_state.stream_terminated = true;
            Poll::Ready(None)
        } else {
            shared_state.waker = Some(cx.waker().clone());
            Poll::Pending
        }
    }
}

impl<K: Eq + Hash + Clone, M> FusedStream for Receiver<K, M> {
    fn is_terminated(&self) -> bool {
        self.shared_state.lock().unwrap().stream_terminated
    }
}

/// Create a new Libra Channel and returns the two ends of the channel.
pub fn new<K: Eq + Hash + Clone, M>(
    queue_style: QueueStyle,
    max_queue_size_per_key: NonZeroUsize,
    counters: Option<&'static IntCounterVec>,
) -> (Sender<K, M>, Receiver<K, M>) {
    let shared_state = Arc::new(Mutex::new(SharedState {
        internal_queue: PerKeyQueue::new(queue_style, max_queue_size_per_key, counters),
        waker: None,
        receiver_dropped: false,
        stream_terminated: false,
    }));
    let shared_state_clone = Arc::clone(&shared_state);
    (
        Sender { shared_state },
        Receiver {
            shared_state: shared_state_clone,
        },
    )
}
<commit_msg>[libra-channel] fix race causing channel close to deadlock<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! libra_channel provides an mpsc channel which has two ends `libra_channel::Receiver`
//! and `libra_channel::Sender` similar to existing mpsc data structures.
//! What makes it different from existing mpsc channels is that we have full control
//! over how the internal queueing in the channel happens and how we schedule messages
//! to be sent out from this channel.
//! Internally, it uses the `PerKeyQueue` to store messages
use crate::message_queues::{PerKeyQueue, QueueStyle};
use anyhow::{ensure, Result};
use futures::{
    channel::oneshot,
    stream::{FusedStream, Stream},
};
use libra_metrics::IntCounterVec;
use std::{
    fmt::{Debug, Formatter},
    hash::Hash,
    num::NonZeroUsize,
    pin::Pin,
    sync::{Arc, Mutex},
    task::{Context, Poll, Waker},
};

/// SharedState is a data structure private to this module which is
/// shared by the `Receiver` and any `Sender`s.
#[derive(Debug)]
struct SharedState<K: Eq + Hash + Clone, M> {
    /// The internal queue of messages in this channel.
    internal_queue: PerKeyQueue<K, (M, Option<oneshot::Sender<ElementStatus<M>>>)>,
    /// The `Receiver` registers its `Waker` in this slot when the queue is empty.
    /// `Sender`s will try to wake the `Receiver` (if any) when they push a new
    /// item onto the queue. The last live `Sender` will also wake the `Receiver`
    /// as it's tearing down so the `Receiver` can gracefully drain and shutdown
    /// the channel.
    waker: Option<Waker>,
    /// The number of active senders. When this value reaches 0, all senders have
    /// been dropped.
    num_senders: usize,
    /// A boolean which tracks whether the receiver has dropped.
    receiver_dropped: bool,
    /// A boolean which tracks whether the stream has terminated. A stream is
    /// considered terminated when sender has dropped and we have drained everything
    /// inside our internal queue.
    stream_terminated: bool,
}

/// The sending end of the libra_channel.
#[derive(Debug)]
pub struct Sender<K: Eq + Hash + Clone, M> {
    shared_state: Arc<Mutex<SharedState<K, M>>>,
}

/// The status of an element inserted into a libra_channel. If the element is successfully
/// dequeued, ElementStatus::Dequeued is sent to the sender. If it is dropped
/// ElementStatus::Dropped is sent to the sender along with the dropped element.
pub enum ElementStatus<M> {
    Dequeued,
    Dropped(M),
}

impl<M: PartialEq> PartialEq for ElementStatus<M> {
    fn eq(&self, other: &ElementStatus<M>) -> bool {
        match (self, other) {
            (ElementStatus::Dequeued, ElementStatus::Dequeued) => true,
            (ElementStatus::Dropped(a), ElementStatus::Dropped(b)) => a.eq(b),
            _ => false,
        }
    }
}

impl<M: Debug> Debug for ElementStatus<M> {
    fn fmt(&self, f: &mut Formatter) -> std::result::Result<(), std::fmt::Error> {
        match self {
            ElementStatus::Dequeued => write!(f, "Dequeued"),
            ElementStatus::Dropped(v) => write!(f, "Dropped({:?})", v),
        }
    }
}

impl<K: Eq + Hash + Clone, M> Sender<K, M> {
    /// This adds the message into the internal queue data structure. This is a
    /// synchronous call.
    pub fn push(&mut self, key: K, message: M) -> Result<()> {
        self.push_with_feedback(key, message, None)
    }

    /// Same as `push`, but this function also accepts a oneshot::Sender over which the sender can
    /// be notified when the message eventually gets delivered or dropped.
    pub fn push_with_feedback(
        &mut self,
        key: K,
        message: M,
        status_ch: Option<oneshot::Sender<ElementStatus<M>>>,
    ) -> Result<()> {
        let mut shared_state = self.shared_state.lock().unwrap();
        ensure!(!shared_state.receiver_dropped, "Channel is closed");
        debug_assert!(shared_state.num_senders > 0);

        let dropped = shared_state.internal_queue.push(key, (message, status_ch));
        // If this or an existing message had to be dropped because of the queue being full, we
        // notify the corresponding status channel if it was registered.
        if let Some((dropped_val, Some(dropped_status_ch))) = dropped {
            // Ignore errors.
            let _err = dropped_status_ch.send(ElementStatus::Dropped(dropped_val));
        }
        if let Some(w) = shared_state.waker.take() {
            w.wake();
        }
        Ok(())
    }
}

impl<K: Eq + Hash + Clone, M> Clone for Sender<K, M> {
    fn clone(&self) -> Self {
        let shared_state = self.shared_state.clone();
        {
            let mut shared_state_lock = shared_state.lock().unwrap();
            debug_assert!(shared_state_lock.num_senders > 0);
            shared_state_lock.num_senders += 1;
        }
        Sender { shared_state }
    }
}

impl<K: Eq + Hash + Clone, M> Drop for Sender<K, M> {
    fn drop(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();

        debug_assert!(shared_state.num_senders > 0);
        shared_state.num_senders -= 1;

        if shared_state.num_senders == 0 {
            if let Some(waker) = shared_state.waker.take() {
                waker.wake();
            }
        }
    }
}

/// The receiving end of the libra_channel.
pub struct Receiver<K: Eq + Hash + Clone, M> {
    shared_state: Arc<Mutex<SharedState<K, M>>>,
}

impl<K: Eq + Hash + Clone, M> Receiver<K, M> {
    /// Removes all the previously sent transactions that have not been consumed yet and cleans up
    /// the internal queue structure (GC of the previous keys).
    pub fn clear(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();
        shared_state.internal_queue.clear();
    }
}

impl<K: Eq + Hash + Clone, M> Drop for Receiver<K, M> {
    fn drop(&mut self) {
        let mut shared_state = self.shared_state.lock().unwrap();
        debug_assert!(!shared_state.receiver_dropped);
        shared_state.receiver_dropped = true;
    }
}

impl<K: Eq + Hash + Clone, M> Stream for Receiver<K, M> {
    type Item = M;
    /// poll_next checks whether there is something ready for consumption from the internal
    /// queue. If there is, then it returns immediately. If the internal_queue is empty,
    /// it sets the waker passed to it by the scheduler/executor and returns Pending
    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut shared_state = self.shared_state.lock().unwrap();
        if let Some((val, status_ch)) = shared_state.internal_queue.pop() {
            if let Some(status_ch) = status_ch {
                let _err = status_ch.send(ElementStatus::Dequeued);
            }
            Poll::Ready(Some(val))
        // all senders have been dropped (and so the stream is terminated)
        } else if shared_state.num_senders == 0 {
            shared_state.stream_terminated = true;
            Poll::Ready(None)
        } else {
            shared_state.waker = Some(cx.waker().clone());
            Poll::Pending
        }
    }
}

impl<K: Eq + Hash + Clone, M> FusedStream for Receiver<K, M> {
    fn is_terminated(&self) -> bool {
        self.shared_state.lock().unwrap().stream_terminated
    }
}

/// Create a new Libra Channel and returns the two ends of the channel.
pub fn new<K: Eq + Hash + Clone, M>(
    queue_style: QueueStyle,
    max_queue_size_per_key: NonZeroUsize,
    counters: Option<&'static IntCounterVec>,
) -> (Sender<K, M>, Receiver<K, M>) {
    let shared_state = Arc::new(Mutex::new(SharedState {
        internal_queue: PerKeyQueue::new(queue_style, max_queue_size_per_key, counters),
        waker: None,
        num_senders: 1,
        receiver_dropped: false,
        stream_terminated: false,
    }));
    let shared_state_clone = Arc::clone(&shared_state);
    (
        Sender { shared_state },
        Receiver {
            shared_state: shared_state_clone,
        },
    )
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate log;
extern crate trust_dns;
extern crate tokio_core;

mod server_harness;

use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(not(feature = "ring"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(feature = "ring")]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty...
    fs::remove_file(&journal).expect("failed to cleanup after test");
}<commit_msg>disable flaky tests on windows<commit_after>#![cfg(not(windows))]

extern crate futures;
extern crate log;
extern crate trust_dns;
extern crate tokio_core;

mod server_harness;

use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(not(feature = "ring"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(feature = "ring")]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty...
    fs::remove_file(&journal).expect("failed to cleanup after test");
}<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Dijkstra's_algorithm

use std::collections::{HashMap, PriorityQueue, DList, Deque};
use std::collections::hashmap::{Occupied, Vacant};
use std::uint;

type Node = uint;
type Cost = uint;
type Edge = (Node, Node);

/// The DistPair struct is for the Priority Queue.
#[deriving(Eq, PartialEq)]
struct DistPair(Node, Cost);
impl Ord for DistPair{
    fn cmp(&self, other:&DistPair) -> Ordering{
        let DistPair(_, dist_a) = *self;
        let DistPair(_, dist_b) = *other;
        dist_b.cmp(&dist_a) //Intentionally reversed
    }
}

impl PartialOrd for DistPair{
    fn partial_cmp(&self, other:&DistPair) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

/// Graph structure, represented as an Adjancency List.
struct Graph<'a>{
    vertices: Vec<&'a str>,
    adj_list: Vec<Vec<Node>>,
    costs: HashMap<Edge, Cost>,
}

impl<'a> Graph<'a> {
    fn new() -> Graph<'a>{
        let vertices:Vec<&str> = Vec::new();
        let adj_list:Vec<Vec<Node>> = Vec::new();
        let costs:HashMap<Edge, Cost> = HashMap::new();

        Graph{vertices: vertices, adj_list: adj_list, costs: costs}
    }

    /// Returns the index of the vertex, or None if vertex
    /// not found.
    fn vertex_index(&self, vertex: &str)->Option<Node>{
        for (idx, &v) in self.vertices.iter().enumerate(){
            if v == vertex{return Some(idx)}
        }
        return None
    }

    /// Returns the index of the vertex. If vertex is not found, inserts
    /// the vertex.
    fn get_or_insert_vertex(&mut self, vertex: &'a str) -> Node {

        let new_idx = match self.vertex_index(vertex){
            Some(idx) => idx,
            None => {
                let new_str = vertex;
                self.adj_list.push(Vec::new());
                self.vertices.push(new_str);
                self.vertices.len()-1
            }
        };
        new_idx
    }

    /// Adds the given edge to the graph.
    fn add_edge(&mut self, from: &'a str, to: &'a str, cost: uint){
        let from_idx = self.get_or_insert_vertex(from);
        let to_idx = self.get_or_insert_vertex(to);

        match self.costs.entry((from_idx, to_idx)){
            Vacant(entry)   => {
                self.adj_list.get_mut(from_idx).push(to_idx);
                entry.set(cost);
            },
            Occupied(entry) => {
                *entry.into_mut() = cost;
            }
        };
    }

    /// Implements Djikstra's Algorithm. This uses a Priority Queue to
    /// determine which vertex to visit first. Terminates on discovering
    /// the target vertex.
    ///
    /// Returns vector of vertices representing the path, or an empty vector
    /// if there's no path, or if the source or target is not in the graph.
    fn dijkstra(&self, source: &str, target: &str)->Vec<&str>{
        let num_vert = self.vertices.len();
        let mut dist:Vec<uint> = Vec::from_elem(num_vert, uint::MAX); //Close enough to infinity
        let mut prev:HashMap<Node, Node> = HashMap::new();
        let mut queue:PriorityQueue<DistPair> = PriorityQueue::new();

        let source_idx = match self.vertex_index(source){
            Some(idx) => idx,
            None      => return Vec::new() // Source not in graph, return empty path.
        };

        let target_idx = match self.vertex_index(target){
            Some(idx) => idx,
            None      => return Vec::new() // Target not in graph, return empty path.
        };

        *dist.get_mut(source_idx) = 0u;
        queue.push(DistPair(source_idx, dist[source_idx]));

        loop{
            match queue.pop(){
                None     => break,
                Some(DistPair(u, dist_u)) => {
                    for &v in self.adj_list[u].iter(){
                        let cost_uv = match self.costs.find(&(u, v)){
                            Some(&x) => x,
                            None    => uint::MAX,
                        };
                        let alt = dist_u + cost_uv;
                        if alt < dist[v] {
                            match prev.entry(v){
                                Vacant(entry) => {entry.set(u);},
                                Occupied(entry) => {
                                    *entry.into_mut() = u;
                                }
                            }
                            *dist.get_mut(v) = alt;
                            queue.push(DistPair(v, dist[v]));
                        }
                        if v == target_idx {break;}
                    }
                }
            };
        }
        let mut temp_path:DList<&str> = DList::new();
        let mut curr = target_idx;
        temp_path.push_front(self.vertices[curr]);
        loop{
            match prev.find(&curr){
                Some(&parent) => {
                    curr = parent;
                    temp_path.push_front(self.vertices[curr]);
                    if curr == source_idx {break;}
                },
                None => return Vec::new(),
            }
        }
        return temp_path.into_iter().collect();
    }
}

#[test]
fn test_dijkstras() {
    let mut graph = Graph::new();
    graph.add_edge("a", "b", 7);
    graph.add_edge("b", "c", 10);
    graph.add_edge("c", "d", 5);
    graph.add_edge("a", "d", 30);
    graph.add_edge("y", "z", 10); //Disconnected from the rest

    assert_eq!(graph.dijkstra("a", "d"), vec!["a", "b", "c", "d"]);
    assert_eq!(graph.dijkstra("a", "y"), vec![]);
    assert_eq!(graph.dijkstra("e", "y"), vec![]);
    assert_eq!(graph.dijkstra("a", "e"), vec![]);
}

#[cfg(not(test))]
fn main(){
    let mut graph = Graph::new();
    graph.add_edge("a", "b", 7);
    graph.add_edge("a", "c", 9);
    graph.add_edge("a", "f", 14);
    graph.add_edge("b", "c", 10);
    graph.add_edge("b", "d", 15);
    graph.add_edge("c", "d", 11);
    graph.add_edge("c", "f", 2);
    graph.add_edge("d", "e", 6);
    graph.add_edge("e", "f", 9);

    let path = graph.dijkstra("a", "e");
    println!("Path is: {}", path);
}

<commit_msg>General style fixes<commit_after>// Implements http://rosettacode.org/wiki/Dijkstra's_algorithm

use std::collections::{HashMap, PriorityQueue, DList, Deque};
use std::collections::hashmap::{Occupied, Vacant};
use std::uint;

type Node = uint;
type Cost = uint;
type Edge = (Node, Node);

/// The DistPair struct is for the Priority Queue.
#[deriving(Eq, PartialEq, PartialOrd)]
struct DistPair(Node, Cost);
impl Ord for DistPair {
    fn cmp(&self, other:&DistPair) -> Ordering {
        let DistPair(_, dist_a) = *self;
        let DistPair(_, dist_b) = *other;
        dist_b.cmp(&dist_a) //Intentionally reversed
    }
}

/// Graph structure, represented as an Adjancency List.
struct Graph<'a> {
    vertices: Vec<&'a str>,
    adj_list: Vec<Vec<Node>>,
    costs: HashMap<Edge, Cost>,
}

impl<'a> Graph<'a> {
    fn new() -> Graph<'a> {
        let vertices:Vec<&str> = Vec::new();
        let adj_list:Vec<Vec<Node>> = Vec::new();
        let costs:HashMap<Edge, Cost> = HashMap::new();

        Graph{vertices: vertices, adj_list: adj_list, costs: costs}
    }

    /// Returns the index of the vertex, or None if vertex
    /// not found.
    fn vertex_index(&self, vertex: &str) -> Option<Node> {
        for (idx, &v) in self.vertices.iter().enumerate(){
            if v == vertex{return Some(idx)}
        }
        return None
    }

    /// Returns the index of the vertex. If vertex is not found, inserts
    /// the vertex.
    fn get_or_insert_vertex(&mut self, vertex: &'a str) -> Node {
        self.vertex_index(vertex)
            .unwrap_or_else( || {
                self.adj_list.push(Vec::new());
                self.vertices.push(vertex);
                self.vertices.len()-1
            })
    }

    /// Adds the given edge to the graph.
    fn add_edge(&mut self, from: &'a str, to: &'a str, cost: uint) {
        let from_idx = self.get_or_insert_vertex(from);
        let to_idx = self.get_or_insert_vertex(to);

        match self.costs.entry((from_idx, to_idx)) {
            Vacant(entry)   => {
                self.adj_list.get_mut(from_idx).push(to_idx);
                entry.set(cost);
            },
            Occupied(entry) => {
                *entry.into_mut() = cost;
            }
        };
    }

    /// Implements Dijkstra's Algorithm. This uses a Priority Queue to
    /// determine which vertex to visit first. Terminates on discovering
    /// the target vertex.
    ///
    /// Returns vector of vertices representing the path, or an empty vector
    /// if there's no path, or if the source or target is not in the graph.
    fn dijkstra(&self, source: &str, target: &str) -> Vec<&str> {
        let num_vert = self.vertices.len();
        let mut dist:Vec<uint> = Vec::from_elem(num_vert, uint::MAX); //Close enough to infinity
        let mut prev:HashMap<Node, Node> = HashMap::new();
        let mut queue:PriorityQueue<DistPair> = PriorityQueue::new();

        let source_idx = match self.vertex_index(source) {
            Some(idx) => idx,
            None      => return Vec::new() // Source not in graph, return empty path.
        };

        let target_idx = match self.vertex_index(target) {
            Some(idx) => idx,
            None      => return Vec::new() // Target not in graph, return empty path.
        };

        *dist.get_mut(source_idx) = 0u;
        queue.push(DistPair(source_idx, dist[source_idx]));

        loop{
            match queue.pop() {
                None     => break,
                Some(DistPair(u, dist_u)) => {
                    for &v in self.adj_list[u].iter() {
                        let cost_uv = match self.costs.find(&(u, v)) {
                            Some(&x) => x,
                            None    => uint::MAX,
                        };
                        let alt = dist_u + cost_uv;
                        if alt < dist[v] {
                            match prev.entry(v) {
                                Vacant(entry) => {entry.set(u);},
                                Occupied(entry) => {
                                    *entry.into_mut() = u;
                                }
                            }
                            *dist.get_mut(v) = alt;
                            queue.push(DistPair(v, dist[v]));
                        }
                        if v == target_idx { break; }
                    }
                }
            };
        }

        let mut temp_path:DList<&str> = DList::new();
        let mut curr = target_idx;
        temp_path.push_front(self.vertices[curr]);
        loop{
            match prev.find(&curr){
                Some(&parent) => {
                    curr = parent;
                    temp_path.push_front(self.vertices[curr]);
                    if curr == source_idx { break; }
                },
                None => return Vec::new(),
            }
        }
        return temp_path.into_iter().collect();
    }
}

#[test]
fn test_dijkstras() {
    let mut graph = Graph::new();
    graph.add_edge("a", "b", 7);
    graph.add_edge("b", "c", 10);
    graph.add_edge("c", "d", 5);
    graph.add_edge("a", "d", 30);
    graph.add_edge("y", "z", 10); //Disconnected from the rest

    assert_eq!(graph.dijkstra("a", "d"), vec!["a", "b", "c", "d"]);
    assert_eq!(graph.dijkstra("a", "y"), vec![]);
    assert_eq!(graph.dijkstra("e", "y"), vec![]);
    assert_eq!(graph.dijkstra("a", "e"), vec![]);
}

#[cfg(not(test))]
fn main(){
    let mut graph = Graph::new();
    graph.add_edge("a", "b", 7);
    graph.add_edge("a", "c", 9);
    graph.add_edge("a", "f", 14);
    graph.add_edge("b", "c", 10);
    graph.add_edge("b", "d", 15);
    graph.add_edge("c", "d", 11);
    graph.add_edge("c", "f", 2);
    graph.add_edge("d", "e", 6);
    graph.add_edge("e", "f", 9);

    let path = graph.dijkstra("a", "e");
    println!("Path is: {}", path);
}

<|endoftext|>


<commit_before>use rustbox;
use yoga;
use yoga_wrapper;

use yoga::Renders;

use Backend;
use Builder;

pub struct Renderer<'rbox> {
    rustbox: &'rbox rustbox::RustBox,
}

impl<'rbox> Renderer<'rbox> {
    pub fn new(rustbox: &rustbox::RustBox) -> Renderer {
        Renderer { rustbox: rustbox }
    }

    fn walk(&mut self, node: &yoga::Renderable<rustbox::Color>) {
        let width = node.get_layout_width() as usize;
        let height = node.get_layout_height() as usize;
        let top = node.get_layout_top() as usize;
        let left = node.get_layout_left() as usize;

        let color = node.get_color();
        let background_color = match *node.get_background_color() {
            Some(yoga::style::BackgroundColor::Transparent) => rustbox::Color::Black,
            Some(yoga::style::BackgroundColor::Color(c)) => c,
            None => rustbox::Color::Black,
        };

        for y in top..(top + height) {
            self.rustbox.print(left,
                               y,
                               rustbox::RB_BOLD,
                               rustbox::Color::White, // TODO use color
                               background_color,
                               &format!("{:1$}", "", width));
        }

        for i in 0..node.get_child_count() {
            let child = node.get_child(i).unwrap();
            self.render(child);
        }
    }
}

impl<'rbox, 'meas> yoga::Renders<'meas> for Renderer<'rbox> {
    type Color = rustbox::Color;
    type Builder = Builder;

    fn render(&mut self, node: &yoga::Renderable<Self::Color>) {
        self.walk(node);
        self.rustbox.present();
    }
}
<commit_msg>feat(renderer): add color; update to render text<commit_after>use rustbox;
use yoga;
use yoga_wrapper;

use yoga::Renders;

use Backend;
use Builder;

pub struct Renderer<'rbox> {
    rustbox: &'rbox rustbox::RustBox,
}

impl<'rbox> Renderer<'rbox> {
    pub fn new(rustbox: &rustbox::RustBox) -> Renderer {
        Renderer { rustbox: rustbox }
    }

    fn walk(&mut self, node: &yoga::Renderable<rustbox::Color>) {
        let width = node.get_layout_width() as usize;
        let height = node.get_layout_height() as usize;
        let top = node.get_layout_top() as usize;
        let left = node.get_layout_left() as usize;

        let color = match *node.get_color() {
            Some(c) => c,
            None => rustbox::Color::White,
        };

        let background_color = match *node.get_background_color() {
            Some(yoga::style::BackgroundColor::Transparent) => rustbox::Color::Black,
            Some(yoga::style::BackgroundColor::Color(c)) => c,
            None => rustbox::Color::Black,
        };

        if let Some(text) = node.get_text() {
            self.rustbox.print(left, top, rustbox::RB_BOLD, color, background_color, text);
        } else {
            for y in top..(top + height) {
                self.rustbox.print(left,
                                   y,
                                   rustbox::RB_BOLD,
                                   color,
                                   background_color,
                                   &format!("{:1$}", "", width));
            }
        }

        for i in 0..node.get_child_count() {
            let child = node.get_child(i).unwrap();
            self.render(child);
        }
    }
}

impl<'rbox, 'meas> yoga::Renders<'meas> for Renderer<'rbox> {
    type Color = rustbox::Color;
    type Builder = Builder;

    fn render(&mut self, node: &yoga::Renderable<Self::Color>) {
        self.walk(node);
        self.rustbox.present();
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json::{self, Json, ToJson};

use common::{Nullable, Date};
use cookie;
use time;

#[derive(Debug)]
pub enum WebDriverResponse {
    CloseWindow(CloseWindowResponse),
    Cookie(CookieResponse),
    DeleteSession,
    ElementRect(ElementRectResponse),
    Generic(ValueResponse),
    NewSession(NewSessionResponse),
    Timeouts(TimeoutsResponse),
    Void,
    WindowRect(WindowRectResponse),
}

impl WebDriverResponse {
    pub fn to_json_string(self) -> String {
        let obj = match self {
            WebDriverResponse::CloseWindow(ref x) => json::encode(&x.to_json()),
            WebDriverResponse::Cookie(ref x) => json::encode(x),
            WebDriverResponse::DeleteSession => Ok("{}".to_string()),
            WebDriverResponse::ElementRect(ref x) => json::encode(x),
            WebDriverResponse::Generic(ref x) => json::encode(x),
            WebDriverResponse::NewSession(ref x) => json::encode(x),
            WebDriverResponse::Timeouts(ref x) => json::encode(x),
            WebDriverResponse::Void => Ok("{}".to_string()),
            WebDriverResponse::WindowRect(ref x) => json::encode(x),
        }.unwrap();

        match self {
            WebDriverResponse::Generic(_) |
            WebDriverResponse::Cookie(_) => obj,
            _ => {
                let mut data = String::with_capacity(11 + obj.len());
                data.push_str("{\"value\": ");
                data.push_str(&*obj);
                data.push_str("}");
                data
            }
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct CloseWindowResponse {
    pub window_handles: Vec<String>,
}

impl CloseWindowResponse {
    pub fn new(handles: Vec<String>) -> CloseWindowResponse {
        CloseWindowResponse { window_handles: handles }
    }
}

impl ToJson for CloseWindowResponse {
    fn to_json(&self) -> Json {
        Json::Array(self.window_handles
                    .iter()
                    .map(|x| Json::String(x.clone()))
                    .collect::<Vec<Json>>())
    }
}

#[derive(RustcEncodable, Debug)]
pub struct NewSessionResponse {
    pub sessionId: String,
    pub capabilities: json::Json
}

impl NewSessionResponse {
    pub fn new(session_id: String, capabilities: json::Json) -> NewSessionResponse {
        NewSessionResponse {
            capabilities: capabilities,
            sessionId: session_id
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct TimeoutsResponse {
    pub script: u64,
    pub pageLoad: u64,
    pub implicit: u64,
}

impl TimeoutsResponse {
    pub fn new(script: u64, page_load: u64, implicit: u64) -> TimeoutsResponse {
        TimeoutsResponse {
            script: script,
            pageLoad: page_load,
            implicit: implicit,
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct ValueResponse {
    pub value: json::Json
}

impl ValueResponse {
    pub fn new(value: json::Json) -> ValueResponse {
        ValueResponse {
            value: value
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct WindowRectResponse {
    pub x: i64,
    pub y: i64,
    pub width: u64,
    pub height: u64,
}

#[derive(RustcEncodable, Debug)]
pub struct ElementRectResponse {
    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64
}

impl ElementRectResponse {
    pub fn new(x: f64, y: f64, width: f64, height: f64) -> ElementRectResponse {
        ElementRectResponse {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

//TODO: some of these fields are probably supposed to be optional
#[derive(RustcEncodable, PartialEq, Debug, Clone)]
pub struct Cookie {
    pub name: String,
    pub value: String,
    pub path: Nullable<String>,
    pub domain: Nullable<String>,
    pub expiry: Nullable<Date>,
    pub secure: bool,
    pub httpOnly: bool
}

impl Cookie {
    pub fn new(name: String, value: String, path: Nullable<String>, domain: Nullable<String>,
               expiry: Nullable<Date>, secure: bool, http_only: bool) -> Cookie {
        Cookie {
            name: name,
            value: value,
            path: path,
            domain: domain,
            expiry: expiry,
            secure: secure,
            httpOnly: http_only
        }
    }
}

impl Into<cookie::Cookie<'static>> for Cookie {
    fn into(self) -> cookie::Cookie<'static> {
        let cookie = cookie::Cookie::build(self.name, self.value)
            .secure(self.secure)
            .http_only(self.httpOnly);
        let cookie = match self.domain {
            Nullable::Value(domain) => cookie.domain(domain),
            Nullable::Null => cookie,
        };
        let cookie = match self.path {
            Nullable::Value(path) => cookie.path(path),
            Nullable::Null => cookie,
        };
        let cookie = match self.expiry {
            Nullable::Value(Date(expiry)) => {
                cookie.expires(time::at(time::Timespec::new(expiry as i64, 0)))
            },
            Nullable::Null => cookie,
        };
        cookie.finish()
    }
}

#[derive(RustcEncodable, Debug)]
pub struct CookieResponse {
    pub value: Vec<Cookie>
}

impl CookieResponse {
    pub fn new(value: Vec<Cookie>) -> CookieResponse {
        CookieResponse {
            value: value
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use rustc_serialize::json::Json;
    use super::{WebDriverResponse,
                CloseWindowResponse,
                CookieResponse,
                ElementRectResponse,
                NewSessionResponse,
                ValueResponse,
                TimeoutsResponse,
                WindowRectResponse,
                Cookie,
                Nullable};

    fn test(resp: WebDriverResponse, expected_str: &str) {
        let data = resp.to_json_string();
        let actual = Json::from_str(&*data).unwrap();
        let expected = Json::from_str(expected_str).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_close_window() {
        let resp = WebDriverResponse::CloseWindow(
            CloseWindowResponse::new(vec!["test".into()]));
        let expected = r#"{"value": ["test"]}"#;
        test(resp, expected);
    }

    #[test]
    fn test_cookie() {
        let resp = WebDriverResponse::Cookie(CookieResponse::new(
            vec![
                Cookie::new("test".into(),
                            "test_value".into(),
                            Nullable::Value("/".into()),
                            Nullable::Null,
                            Nullable::Null,
                            true,
                            false)
            ]));
        let expected = r#"{"value": [{"name": "test", "value": "test_value", "path": "/",
"domain": null, "expiry": null, "secure": true, "httpOnly": false}]}"#;
        test(resp, expected);
    }

    #[test]
    fn test_element_rect() {
        let resp = WebDriverResponse::ElementRect(ElementRectResponse::new(
            0f64, 1f64, 2f64, 3f64));
        let expected = r#"{"value": {"x": 0.0, "y": 1.0, "width": 2.0, "height": 3.0}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_window_rect() {
        let resp = WebDriverResponse::WindowRect(WindowRectResponse {
            x: 0i64,
            y: 1i64,
            width: 2u64,
            height: 3u64,
        });
        let expected = r#"{"value": {"x": 0, "y": 1, "width": 2, "height": 3}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_new_session() {
        let resp = WebDriverResponse::NewSession(
            NewSessionResponse::new("test".into(),
                                    Json::Object(BTreeMap::new())));
        let expected = r#"{"value": {"sessionId": "test", "capabilities": {}}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_timeouts() {
         let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new(
            1, 2, 3));
        let expected = r#"{"value": {"script": 1, "pageLoad": 2, "implicit": 3}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_value() {
        let mut value = BTreeMap::new();
        value.insert("example".into(), Json::Array(vec![Json::String("test".into())]));
        let resp = WebDriverResponse::Generic(ValueResponse::new(
            Json::Object(value)));
        let expected = r#"{"value": {"example": ["test"]}}"#;
        test(resp, expected);
    }
}
<commit_msg>Simplify Responses for Rect type calls to use same struct and impl (#101)<commit_after>use rustc_serialize::json::{self, Json, ToJson};

use common::{Nullable, Date};
use cookie;
use time;

#[derive(Debug)]
pub enum WebDriverResponse {
    CloseWindow(CloseWindowResponse),
    Cookie(CookieResponse),
    DeleteSession,
    ElementRect(RectResponse),
    Generic(ValueResponse),
    NewSession(NewSessionResponse),
    Timeouts(TimeoutsResponse),
    Void,
    WindowRect(RectResponse),
}

impl WebDriverResponse {
    pub fn to_json_string(self) -> String {
        let obj = match self {
            WebDriverResponse::CloseWindow(ref x) => json::encode(&x.to_json()),
            WebDriverResponse::Cookie(ref x) => json::encode(x),
            WebDriverResponse::DeleteSession => Ok("{}".to_string()),
            WebDriverResponse::ElementRect(ref x) => json::encode(x),
            WebDriverResponse::Generic(ref x) => json::encode(x),
            WebDriverResponse::NewSession(ref x) => json::encode(x),
            WebDriverResponse::Timeouts(ref x) => json::encode(x),
            WebDriverResponse::Void => Ok("{}".to_string()),
            WebDriverResponse::WindowRect(ref x) => json::encode(x),
        }.unwrap();

        match self {
            WebDriverResponse::Generic(_) |
            WebDriverResponse::Cookie(_) => obj,
            _ => {
                let mut data = String::with_capacity(11 + obj.len());
                data.push_str("{\"value\": ");
                data.push_str(&*obj);
                data.push_str("}");
                data
            }
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct CloseWindowResponse {
    pub window_handles: Vec<String>,
}

impl CloseWindowResponse {
    pub fn new(handles: Vec<String>) -> CloseWindowResponse {
        CloseWindowResponse { window_handles: handles }
    }
}

impl ToJson for CloseWindowResponse {
    fn to_json(&self) -> Json {
        Json::Array(self.window_handles
                    .iter()
                    .map(|x| Json::String(x.clone()))
                    .collect::<Vec<Json>>())
    }
}

#[derive(RustcEncodable, Debug)]
pub struct NewSessionResponse {
    pub sessionId: String,
    pub capabilities: json::Json
}

impl NewSessionResponse {
    pub fn new(session_id: String, capabilities: json::Json) -> NewSessionResponse {
        NewSessionResponse {
            capabilities: capabilities,
            sessionId: session_id
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct TimeoutsResponse {
    pub script: u64,
    pub pageLoad: u64,
    pub implicit: u64,
}

impl TimeoutsResponse {
    pub fn new(script: u64, page_load: u64, implicit: u64) -> TimeoutsResponse {
        TimeoutsResponse {
            script: script,
            pageLoad: page_load,
            implicit: implicit,
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct ValueResponse {
    pub value: json::Json
}

impl ValueResponse {
    pub fn new(value: json::Json) -> ValueResponse {
        ValueResponse {
            value: value
        }
    }
}

#[derive(RustcEncodable, Debug)]
pub struct RectResponse {
    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64
}

impl RectResponse {
    pub fn new(x: f64, y: f64, width: f64, height: f64) -> RectResponse {
        RectResponse {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

//TODO: some of these fields are probably supposed to be optional
#[derive(RustcEncodable, PartialEq, Debug, Clone)]
pub struct Cookie {
    pub name: String,
    pub value: String,
    pub path: Nullable<String>,
    pub domain: Nullable<String>,
    pub expiry: Nullable<Date>,
    pub secure: bool,
    pub httpOnly: bool
}

impl Cookie {
    pub fn new(name: String, value: String, path: Nullable<String>, domain: Nullable<String>,
               expiry: Nullable<Date>, secure: bool, http_only: bool) -> Cookie {
        Cookie {
            name: name,
            value: value,
            path: path,
            domain: domain,
            expiry: expiry,
            secure: secure,
            httpOnly: http_only
        }
    }
}

impl Into<cookie::Cookie<'static>> for Cookie {
    fn into(self) -> cookie::Cookie<'static> {
        let cookie = cookie::Cookie::build(self.name, self.value)
            .secure(self.secure)
            .http_only(self.httpOnly);
        let cookie = match self.domain {
            Nullable::Value(domain) => cookie.domain(domain),
            Nullable::Null => cookie,
        };
        let cookie = match self.path {
            Nullable::Value(path) => cookie.path(path),
            Nullable::Null => cookie,
        };
        let cookie = match self.expiry {
            Nullable::Value(Date(expiry)) => {
                cookie.expires(time::at(time::Timespec::new(expiry as i64, 0)))
            },
            Nullable::Null => cookie,
        };
        cookie.finish()
    }
}

#[derive(RustcEncodable, Debug)]
pub struct CookieResponse {
    pub value: Vec<Cookie>
}

impl CookieResponse {
    pub fn new(value: Vec<Cookie>) -> CookieResponse {
        CookieResponse {
            value: value
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use rustc_serialize::json::Json;
    use super::{WebDriverResponse,
                CloseWindowResponse,
                CookieResponse,
                RectResponse,
                NewSessionResponse,
                ValueResponse,
                TimeoutsResponse,
                Cookie,
                Nullable};

    fn test(resp: WebDriverResponse, expected_str: &str) {
        let data = resp.to_json_string();
        let actual = Json::from_str(&*data).unwrap();
        let expected = Json::from_str(expected_str).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_close_window() {
        let resp = WebDriverResponse::CloseWindow(
            CloseWindowResponse::new(vec!["test".into()]));
        let expected = r#"{"value": ["test"]}"#;
        test(resp, expected);
    }

    #[test]
    fn test_cookie() {
        let resp = WebDriverResponse::Cookie(CookieResponse::new(
            vec![
                Cookie::new("test".into(),
                            "test_value".into(),
                            Nullable::Value("/".into()),
                            Nullable::Null,
                            Nullable::Null,
                            true,
                            false)
            ]));
        let expected = r#"{"value": [{"name": "test", "value": "test_value", "path": "/",
"domain": null, "expiry": null, "secure": true, "httpOnly": false}]}"#;
        test(resp, expected);
    }

    #[test]
    fn test_element_rect() {
        let resp = WebDriverResponse::ElementRect(RectResponse::new(
            0f64, 1f64, 2f64, 3f64));
        let expected = r#"{"value": {"x": 0.0, "y": 1.0, "width": 2.0, "height": 3.0}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_window_rect() {
        let resp = WebDriverResponse::WindowRect(RectResponse {
            x: 0f64,
            y: 1f64,
            width: 2f64,
            height: 3f64,
        });
        let expected = r#"{"value": {"x": 0.0, "y": 1.0, "width": 2.0, "height": 3.0}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_new_session() {
        let resp = WebDriverResponse::NewSession(
            NewSessionResponse::new("test".into(),
                                    Json::Object(BTreeMap::new())));
        let expected = r#"{"value": {"sessionId": "test", "capabilities": {}}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_timeouts() {
         let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new(
            1, 2, 3));
        let expected = r#"{"value": {"script": 1, "pageLoad": 2, "implicit": 3}}"#;
        test(resp, expected);
    }

    #[test]
    fn test_value() {
        let mut value = BTreeMap::new();
        value.insert("example".into(), Json::Array(vec![Json::String("test".into())]));
        let resp = WebDriverResponse::Generic(ValueResponse::new(
            Json::Object(value)));
        let expected = r#"{"value": {"example": ["test"]}}"#;
        test(resp, expected);
    }
}
<|endoftext|>