<commit_before>use std::collections::HashMap;
use graph_match::graph::Graph;
us graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v(),
        np_v_np(),
        np_v_adj(),
        np_v_adv(),
        np_v_adv_lex(),
        np_v_adv_prep_np(),
        lex_v_np_prep_np(),
        lex_v_prep_np_np(),
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:edge identifier:obj source:1 target:0 label:nsubj";
    return (String::from("NP VERB"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod";
    return (String::from("NP VERB ADV"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("NP VERB ADV PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// lex should be before avd
fn np_v_adv_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:adv\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:adv source:1 target:3 label:advmod\n\
                        type:edge identifier:lex source:1 target:4 label:advmod";
    return (String::from("NP VERB ADV LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn lex_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:dobj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("LEX VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// uses generic dependency, this should not expand.
fn lex_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:dep\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:dep source:2 target:4 label:dep";
    return (String::from("LEX VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// copula frames
fn copula_np_v_adj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:xcomp source:1 target:2 label:xcomp";
    return (String::from("copula:NP VERB ADJ"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

<commit_msg>Add frame details for a number of verb frames<commit_after>use std::collections::HashMap;
use graph_match::graph::Graph;
use graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v(),
        np_v_np(),
        np_v_adv(),
        np_v_adv_lex(),
        np_v_adv_prep_np(),
        lex_v_np_prep_np(),
        lex_v_prep_np_np(),
        np_v_prep_np(),
        np_v_prep_np_prep_np(),
        np_v_np_prep_np(),
        prep_np_v_np(),

        copula_np_v_adj(),
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:edge identifier:obj source:1 target:0 label:nsubj";
    return (String::from("NP VERB"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod";
    return (String::from("NP VERB ADV"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case";
    return (String::from("NP VERB PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:np3\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:4 label:nmod\n\
                        type:edge identifier:case source:4 target:3 label:case";
    return (String::from("NP VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// this requires a more fuzzy match on clausal relations that are assumed not to exist elsewhere
fn np_v_prep_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:verb2 pos:VB\n\
                        type:node identifier:prep2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:advcl source:4 target:1 label:advcl\n\
                        type:edge identifier:case source:4 target:5 label:case";
    return (String::from("NP VERB PREP NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("NP VERB ADV PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// lex should be before avd
fn np_v_adv_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:adv\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:adv source:1 target:3 label:advmod\n\
                        type:edge identifier:lex source:1 target:4 label:advmod";
    return (String::from("NP VERB ADV LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn prep_np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:prep\n\
                        type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:nmod source:2 target:1 label:nmod\n\
                        type:edge identifier:obj source:2 target:3 label:dobj\n\
                        type:edge identifier:case source:1 target:0 label:case";
    return (String::from("PREP NP VERB NP"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn lex_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:dobj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("LEX VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// uses generic dependency, this should not expand.
fn lex_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:dep\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:dep source:2 target:4 label:dep";
    return (String::from("LEX VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// copula frames
fn copula_np_v_adj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:xcomp source:1 target:2 label:xcomp";
    return (String::from("copula:NP VERB ADJ"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

<|endoftext|>


<commit_before>use protobuf::MessageFull;

use super::test_optional_pb::*;

#[test]
fn test() {
    let _message = TestOptionalProto3::new();
}

#[test]
fn field_types() {
    let message = TestOptionalProto3::new();
    let _iii: &Option<i32> = &message.iii;
    let _sss: &Option<String> = &message.sss;
}

#[test]
fn reflect_all_oneofs() {
    let descriptor = TestOptionalProto3::descriptor_static();
    let oneofs = descriptor.all_oneofs().collect::<Vec<_>>();
    assert!(oneofs.len() > 1);
    assert!(!oneofs[0].is_synthetic());
    for oneof in &oneofs[1..] {
        assert!(oneof.is_synthetic());
        let mut fields = oneof.fields().collect::<Vec<_>>();
        assert_eq!(1, fields.len());
        let field = fields.swap_remove(0);
        assert_eq!(None, field.containing_oneof());
        assert_eq!(
            Some(oneof),
            field.containing_oneof_including_synthetic().as_ref()
        );
    }
}

#[test]
fn reflect_oneofs() {
    let descriptor = TestOptionalProto3::descriptor_static();
    let oneofs = descriptor.oneofs().collect::<Vec<_>>();
    assert_eq!(1, oneofs.len());
    assert!(!oneofs[0].is_synthetic());
}
<commit_msg>Test serialize/deserialize proto3 optional<commit_after>use protobuf::MessageFull;
use protobuf_test_common::test_serialize_deserialize_with_dynamic;

use super::test_optional_pb::*;

#[test]
fn serialize_deserialize() {
    let mut message = TestOptionalProto3::new();
    message.iii = Some(0x1a);
    test_serialize_deserialize_with_dynamic("f8 01 1a", &message);
}

#[test]
fn field_types() {
    let message = TestOptionalProto3::new();
    let _iii: &Option<i32> = &message.iii;
    let _sss: &Option<String> = &message.sss;
}

#[test]
fn reflect_all_oneofs() {
    let descriptor = TestOptionalProto3::descriptor_static();
    let oneofs = descriptor.all_oneofs().collect::<Vec<_>>();
    assert!(oneofs.len() > 1);
    assert!(!oneofs[0].is_synthetic());
    for oneof in &oneofs[1..] {
        assert!(oneof.is_synthetic());
        let mut fields = oneof.fields().collect::<Vec<_>>();
        assert_eq!(1, fields.len());
        let field = fields.swap_remove(0);
        assert_eq!(None, field.containing_oneof());
        assert_eq!(
            Some(oneof),
            field.containing_oneof_including_synthetic().as_ref()
        );
    }
}

#[test]
fn reflect_oneofs() {
    let descriptor = TestOptionalProto3::descriptor_static();
    let oneofs = descriptor.oneofs().collect::<Vec<_>>();
    assert_eq!(1, oneofs.len());
    assert!(!oneofs[0].is_synthetic());
}
<|endoftext|>


<commit_before>use crate::common::util::*;

use std::path::Path;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[test]
fn test_realpath_current_directory() {
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = at.root_dir_resolved() + "\n";
    ucmd.arg(".").succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let expect = at.root_dir_resolved() + "\n";
    ucmd.arg(dir).succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let expect = get_root_path().to_owned() + "\n";
    new_ucmd!().arg(dir).succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_file_and_links() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("foo").succeeds().stdout_contains("foo\n");
    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_realpath_file_and_links_zero() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");

    scene
        .ucmd()
        .arg("bar")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");
}

#[test]
fn test_realpath_file_and_links_strip() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-s")
        .succeeds()
        .stdout_contains("foo\n");

    scene
        .ucmd()
        .arg("bar")
        .arg("-s")
        .succeeds()
        .stdout_contains("bar\n");
}

#[test]
fn test_realpath_file_and_links_strip_zero() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-s")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");

    scene
        .ucmd()
        .arg("bar")
        .arg("-s")
        .arg("-z")
        .succeeds()
        .stdout_contains("bar\u{0}");
}

#[test]
fn test_realpath_physical_mode() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.mkdir("dir1");
    at.mkdir_all("dir2/bar");
    at.symlink_dir("dir2/bar", "dir1/foo");

    scene
        .ucmd()
        .arg("dir1/foo/..")
        .succeeds()
        .stdout_contains("dir2\n");
}

#[test]
fn test_realpath_logical_mode() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.mkdir("dir1");
    at.mkdir("dir2");
    at.symlink_dir("dir2", "dir1/foo");

    scene
        .ucmd()
        .arg("-L")
        .arg("dir1/foo/..")
        .succeeds()
        .stdout_contains("dir1\n");
}

#[test]
fn test_realpath_dangling() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.symlink_file("nonexistent-file", "link");
    ucmd.arg("link")
        .fails()
        .stderr_contains("realpath: link: No such file or directory");
}

#[test]
fn test_realpath_loop() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.symlink_file("2", "1");
    at.symlink_file("3", "2");
    at.symlink_file("1", "3");
    ucmd.arg("1")
        .succeeds()
        .stdout_only(at.plus_as_string("2\n"));
}

#[test]
fn test_realpath_default_allows_final_non_existent() {
    let p = Path::new("").join(GIBBERISH);
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
    ucmd.arg(p.as_os_str()).succeeds().stdout_only(expect);
}

#[test]
fn test_realpath_default_forbids_non_final_non_existent() {
    let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
    new_ucmd!().arg(p.to_str().unwrap()).fails();
}

#[test]
fn test_realpath_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    ucmd.arg("-e")
        .arg(".")
        .succeeds()
        .stdout_only(at.plus_as_string(&format!("{}\n", at.root_dir_resolved())));
}

#[test]
fn test_realpath_existing_error() {
    new_ucmd!().arg("-e").arg(GIBBERISH).fails();
}

#[test]
fn test_realpath_missing() {
    let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
    ucmd.arg("-m")
        .arg(p.as_os_str())
        .succeeds()
        .stdout_only(expect);
}

#[test]
fn test_realpath_when_symlink_is_absolute_and_enoent() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("dir2");
    at.touch("dir2/bar");

    at.mkdir("dir1");
    at.symlink_file("dir2/bar", "dir1/foo1");
    at.symlink_file("/dir2/bar", "dir1/foo2");
    at.relative_symlink_file("../dir2/baz", "dir1/foo3");

    #[cfg(unix)]
    ucmd.arg("dir1/foo1")
        .arg("dir1/foo2")
        .arg("dir1/foo3")
        .run()
        .stdout_contains("/dir2/bar\n")
        .stdout_contains("/dir2/baz\n")
        .stderr_is("realpath: dir1/foo2: No such file or directory\n");

    #[cfg(windows)]
    ucmd.arg("dir1/foo1")
        .arg("dir1/foo2")
        .arg("dir1/foo3")
        .run()
        .stdout_contains("\\dir2\\bar\n")
        .stdout_contains("\\dir2\\baz\n")
        .stderr_is("realpath: dir1/foo2: No such file or directory");
}

#[test]
#[ignore]
fn test_realpath_when_symlink_part_is_missing() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("dir2");
    at.touch("dir2/bar");

    at.mkdir("dir1");
    at.relative_symlink_file("../dir2/bar", "dir1/foo1");
    at.relative_symlink_file("dir2/bar", "dir1/foo2");
    at.relative_symlink_file("../dir2/baz", "dir1/foo3");
    at.symlink_file("dir3/bar", "dir1/foo4");

    ucmd.args(&["dir1/foo1", "dir1/foo2", "dir1/foo3", "dir1/foo4"])
        .run()
        .stdout_contains(at.plus_as_string("dir2/bar") + "\n")
        .stdout_contains(at.plus_as_string("dir2/baz") + "\n")
        .stderr_contains("realpath: dir1/foo2: No such file or directory\n")
        .stderr_contains("realpath: dir1/foo4: No such file or directory\n");
}
<commit_msg>test_realpath: include issue id to ignored testcase<commit_after>use crate::common::util::*;

use std::path::Path;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[test]
fn test_realpath_current_directory() {
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = at.root_dir_resolved() + "\n";
    ucmd.arg(".").succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let expect = at.root_dir_resolved() + "\n";
    ucmd.arg(dir).succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let expect = get_root_path().to_owned() + "\n";
    new_ucmd!().arg(dir).succeeds().stdout_is(expect);
}

#[test]
fn test_realpath_file_and_links() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("foo").succeeds().stdout_contains("foo\n");
    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_realpath_file_and_links_zero() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");

    scene
        .ucmd()
        .arg("bar")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");
}

#[test]
fn test_realpath_file_and_links_strip() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-s")
        .succeeds()
        .stdout_contains("foo\n");

    scene
        .ucmd()
        .arg("bar")
        .arg("-s")
        .succeeds()
        .stdout_contains("bar\n");
}

#[test]
fn test_realpath_file_and_links_strip_zero() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene
        .ucmd()
        .arg("foo")
        .arg("-s")
        .arg("-z")
        .succeeds()
        .stdout_contains("foo\u{0}");

    scene
        .ucmd()
        .arg("bar")
        .arg("-s")
        .arg("-z")
        .succeeds()
        .stdout_contains("bar\u{0}");
}

#[test]
fn test_realpath_physical_mode() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.mkdir("dir1");
    at.mkdir_all("dir2/bar");
    at.symlink_dir("dir2/bar", "dir1/foo");

    scene
        .ucmd()
        .arg("dir1/foo/..")
        .succeeds()
        .stdout_contains("dir2\n");
}

#[test]
fn test_realpath_logical_mode() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.mkdir("dir1");
    at.mkdir("dir2");
    at.symlink_dir("dir2", "dir1/foo");

    scene
        .ucmd()
        .arg("-L")
        .arg("dir1/foo/..")
        .succeeds()
        .stdout_contains("dir1\n");
}

#[test]
fn test_realpath_dangling() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.symlink_file("nonexistent-file", "link");
    ucmd.arg("link")
        .fails()
        .stderr_contains("realpath: link: No such file or directory");
}

#[test]
fn test_realpath_loop() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.symlink_file("2", "1");
    at.symlink_file("3", "2");
    at.symlink_file("1", "3");
    ucmd.arg("1")
        .succeeds()
        .stdout_only(at.plus_as_string("2\n"));
}

#[test]
fn test_realpath_default_allows_final_non_existent() {
    let p = Path::new("").join(GIBBERISH);
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
    ucmd.arg(p.as_os_str()).succeeds().stdout_only(expect);
}

#[test]
fn test_realpath_default_forbids_non_final_non_existent() {
    let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
    new_ucmd!().arg(p.to_str().unwrap()).fails();
}

#[test]
fn test_realpath_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    ucmd.arg("-e")
        .arg(".")
        .succeeds()
        .stdout_only(at.plus_as_string(&format!("{}\n", at.root_dir_resolved())));
}

#[test]
fn test_realpath_existing_error() {
    new_ucmd!().arg("-e").arg(GIBBERISH).fails();
}

#[test]
fn test_realpath_missing() {
    let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
    let (at, mut ucmd) = at_and_ucmd!();
    let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
    ucmd.arg("-m")
        .arg(p.as_os_str())
        .succeeds()
        .stdout_only(expect);
}

#[test]
fn test_realpath_when_symlink_is_absolute_and_enoent() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("dir2");
    at.touch("dir2/bar");

    at.mkdir("dir1");
    at.symlink_file("dir2/bar", "dir1/foo1");
    at.symlink_file("/dir2/bar", "dir1/foo2");
    at.relative_symlink_file("../dir2/baz", "dir1/foo3");

    #[cfg(unix)]
    ucmd.arg("dir1/foo1")
        .arg("dir1/foo2")
        .arg("dir1/foo3")
        .run()
        .stdout_contains("/dir2/bar\n")
        .stdout_contains("/dir2/baz\n")
        .stderr_is("realpath: dir1/foo2: No such file or directory\n");

    #[cfg(windows)]
    ucmd.arg("dir1/foo1")
        .arg("dir1/foo2")
        .arg("dir1/foo3")
        .run()
        .stdout_contains("\\dir2\\bar\n")
        .stdout_contains("\\dir2\\baz\n")
        .stderr_is("realpath: dir1/foo2: No such file or directory");
}

#[test]
#[ignore = "issue #3669"]
fn test_realpath_when_symlink_part_is_missing() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("dir2");
    at.touch("dir2/bar");

    at.mkdir("dir1");
    at.relative_symlink_file("../dir2/bar", "dir1/foo1");
    at.relative_symlink_file("dir2/bar", "dir1/foo2");
    at.relative_symlink_file("../dir2/baz", "dir1/foo3");
    at.symlink_file("dir3/bar", "dir1/foo4");

    ucmd.args(&["dir1/foo1", "dir1/foo2", "dir1/foo3", "dir1/foo4"])
        .run()
        .stdout_contains(at.plus_as_string("dir2/bar") + "\n")
        .stdout_contains(at.plus_as_string("dir2/baz") + "\n")
        .stderr_contains("realpath: dir1/foo2: No such file or directory\n")
        .stderr_contains("realpath: dir1/foo4: No such file or directory\n");
}
<|endoftext|>


<commit_before>#![feature(c_unwind)]

extern "C" fn panic_abort() {
    //~ ERROR: the program aborted
    panic!()
}

fn main() {
    panic_abort();
}
<commit_msg>Manual adjustments<commit_after>#![feature(c_unwind)]

extern "C" fn panic_abort() {
    //~^ ERROR: the program aborted
    panic!()
}

fn main() {
    panic_abort();
}
<|endoftext|>


<commit_before>use neon::js::{JsString, JsNumber, JsValue};
use neon::vm::{Call, JsResult};
use neon::js::class::{Class, JsClass};
use neon::mem::Handle;

pub struct User {
  id: i32,
  first_name: String,
  last_name: String,
  email: String,
}

declare_types! {
  pub class JsUser for User {
    init(call) {
      let scope = call.scope;
      let id = try!(try!(call.arguments.require(scope, 0)).check::<JsNumber>());
      let first_name: Handle<JsString> = try!(try!(call.arguments.require(scope, 1)).check::<JsString>());
      let last_name: Handle<JsString> = try!(try!(call.arguments.require(scope, 2)).check::<JsString>());
      let email: Handle<JsString> = try!(try!(call.arguments.require(scope, 3)).check::<JsString>());

      Ok(User {
        id: id.value() as i32,
        first_name: first_name.value(),
        last_name: last_name.value(),
        email: email.value(),
      })
    }
  }
}

register_module!(m, {
  let scope = m.scope;
  let class = try!(JsUser::class(scope));       // get the class
  let constructor = try!(class.constructor(scope)); // get the constructor
  try!(m.exports.set("User", constructor));     // export the constructor
  Ok()
});

pub fn return_js_class(call: Call) -> JsResult<JsClass> {
    let scope = call.scope;
    let ctor = JsUser::constructor(scope);
    let args: Vec<Handle<JsValue>> = vec![];
    let user = try!(ctor.construct(scope, args));
}
<commit_msg>Few refinements<commit_after>use neon::js::{JsString, JsNumber, JsValue, JsObject, Object};
use neon::vm::{Call, JsResult};
use neon::js::class::{Class, JsClass};
use neon::mem::Handle;

pub struct User {
  id: i32,
  first_name: String,
  last_name: String,
  email: String,
}

declare_types! {
  pub class JsUser for User {
    init(call) {
      let scope = call.scope;
      let id = try!(try!(call.arguments.require(scope, 0)).check::<JsNumber>());
      let first_name: Handle<JsString> = try!(try!(call.arguments.require(scope, 1)).check::<JsString>());
      let last_name: Handle<JsString> = try!(try!(call.arguments.require(scope, 2)).check::<JsString>());
      let email: Handle<JsString> = try!(try!(call.arguments.require(scope, 3)).check::<JsString>());

      Ok(User {
        id: id.value() as i32,
        first_name: first_name.value(),
        last_name: last_name.value(),
        email: email.value(),
      })
    }
  }
}

register_module!(m, {
  let scope = m.scope;
  let class = try!(JsUser::class(scope));       // get the class
  let constructor = try!(class.constructor(scope)); // get the constructor
  try!(m.exports.set("User", constructor));     // export the constructor
  Ok(())
});

pub fn return_js_class<T: Class>(call: Call) -> JsResult<JsClass<T>> {
    let scope = call.scope;
    let ctor = JsUser::constructor(scope);
    let args: Vec<Handle<JsValue>> = vec![];
    let user = try!(ctor.construct(scope, args));
}
<|endoftext|>


<commit_before>use crate::types::GossipKind;
use crate::Enr;
use discv5::{Discv5Config, Discv5ConfigBuilder};
use libp2p::gossipsub::{
    GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId, ValidationMode,
};
use libp2p::Multiaddr;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::time::Duration;

pub const GOSSIP_MAX_SIZE: usize = 1_048_576;

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// The address to broadcast to peers about which address we are listening on. None indicates
    /// that no discovery address has been set in the CLI args.
    pub enr_address: Option<std::net::IpAddr>,

    /// The udp port to broadcast to peers in order to reach back for discovery.
    pub enr_udp_port: Option<u16>,

    /// The tcp port to broadcast to peers in order to reach back for libp2p services.
    pub enr_tcp_port: Option<u16>,

    /// Target number of connected peers.
    pub target_peers: usize,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// Discv5 configuration parameters.
    #[serde(skip)]
    pub discv5_config: Discv5Config,

    /// List of nodes to initially connect to.
    pub boot_nodes_enr: Vec<Enr>,

    /// List of nodes to initially connect to, on Multiaddr format.
    pub boot_nodes_multiaddr: Vec<Multiaddr>,

    /// List of libp2p nodes to initially connect to.
    pub libp2p_nodes: Vec<Multiaddr>,

    /// Client version
    pub client_version: String,

    /// Disables the discovery protocol from starting.
    pub disable_discovery: bool,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<GossipKind>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");

        // The default topics that we will initially subscribe to
        let topics = vec![
            GossipKind::BeaconBlock,
            GossipKind::BeaconAggregateAndProof,
            GossipKind::VoluntaryExit,
            GossipKind::ProposerSlashing,
            GossipKind::AttesterSlashing,
        ];

        // The function used to generate a gossipsub message id
        // We use the first 8 bytes of SHA256(data) for content addressing
        let gossip_message_id =
            |message: &GossipsubMessage| MessageId::from(&Sha256::digest(&message.data)[..8]);

        // gossipsub configuration
        // Note: The topics by default are sent as plain strings. Hashes are an optional
        // parameter.
        let gs_config = GossipsubConfigBuilder::new()
            .max_transmit_size(GOSSIP_MAX_SIZE)
            .heartbeat_interval(Duration::from_millis(700))
            .mesh_n(8)
            .mesh_n_low(6)
            .mesh_n_high(12)
            .gossip_lazy(6)
            .fanout_ttl(Duration::from_secs(60))
            .history_length(6)
            .history_gossip(3)
            .validate_messages() // require validation before propagation
            .validation_mode(ValidationMode::Permissive)
            // prevent duplicates for 550 heartbeats(700millis * 550) = 385 secs
            .duplicate_cache_time(Duration::from_secs(385))
            .message_id_fn(gossip_message_id)
            .build()
            .expect("valid gossipsub configuration");

        // discv5 configuration
        let discv5_config = Discv5ConfigBuilder::new()
            .enable_packet_filter()
            .session_cache_capacity(1000)
            .request_timeout(Duration::from_secs(4))
            .request_retries(1)
            .enr_peer_update_min(10)
            .query_parallelism(5)
            .query_timeout(Duration::from_secs(30))
            .query_peer_timeout(Duration::from_secs(2))
            .ip_limit() // limits /24 IP's in buckets.
            .ping_interval(Duration::from_secs(300))
            .build();

        // NOTE: Some of these get overridden by the corresponding CLI default values.
        Config {
            network_dir,
            listen_address: "0.0.0.0".parse().expect("valid ip address"),
            libp2p_port: 9000,
            discovery_port: 9000,
            enr_address: None,
            enr_udp_port: None,
            enr_tcp_port: None,
            target_peers: 50,
            gs_config,
            discv5_config,
            boot_nodes_enr: vec![],
            boot_nodes_multiaddr: vec![],
            libp2p_nodes: vec![],
            client_version: lighthouse_version::version_with_platform(),
            disable_discovery: false,
            topics,
        }
    }
}
<commit_msg>Shift gossipsub validation (#1612)<commit_after>use crate::types::GossipKind;
use crate::Enr;
use discv5::{Discv5Config, Discv5ConfigBuilder};
use libp2p::gossipsub::{
    GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId, ValidationMode,
};
use libp2p::Multiaddr;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::time::Duration;

pub const GOSSIP_MAX_SIZE: usize = 1_048_576;

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// The address to broadcast to peers about which address we are listening on. None indicates
    /// that no discovery address has been set in the CLI args.
    pub enr_address: Option<std::net::IpAddr>,

    /// The udp port to broadcast to peers in order to reach back for discovery.
    pub enr_udp_port: Option<u16>,

    /// The tcp port to broadcast to peers in order to reach back for libp2p services.
    pub enr_tcp_port: Option<u16>,

    /// Target number of connected peers.
    pub target_peers: usize,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// Discv5 configuration parameters.
    #[serde(skip)]
    pub discv5_config: Discv5Config,

    /// List of nodes to initially connect to.
    pub boot_nodes_enr: Vec<Enr>,

    /// List of nodes to initially connect to, on Multiaddr format.
    pub boot_nodes_multiaddr: Vec<Multiaddr>,

    /// List of libp2p nodes to initially connect to.
    pub libp2p_nodes: Vec<Multiaddr>,

    /// Client version
    pub client_version: String,

    /// Disables the discovery protocol from starting.
    pub disable_discovery: bool,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<GossipKind>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");

        // The default topics that we will initially subscribe to
        let topics = vec![
            GossipKind::BeaconBlock,
            GossipKind::BeaconAggregateAndProof,
            GossipKind::VoluntaryExit,
            GossipKind::ProposerSlashing,
            GossipKind::AttesterSlashing,
        ];

        // The function used to generate a gossipsub message id
        // We use the first 8 bytes of SHA256(data) for content addressing
        let gossip_message_id =
            |message: &GossipsubMessage| MessageId::from(&Sha256::digest(&message.data)[..8]);

        // gossipsub configuration
        // Note: The topics by default are sent as plain strings. Hashes are an optional
        // parameter.
        let gs_config = GossipsubConfigBuilder::new()
            .max_transmit_size(GOSSIP_MAX_SIZE)
            .heartbeat_interval(Duration::from_millis(700))
            .mesh_n(8)
            .mesh_n_low(6)
            .mesh_n_high(12)
            .gossip_lazy(6)
            .fanout_ttl(Duration::from_secs(60))
            .history_length(6)
            .history_gossip(3)
            .validate_messages() // require validation before propagation
            .validation_mode(ValidationMode::Anonymous)
            // prevent duplicates for 550 heartbeats(700millis * 550) = 385 secs
            .duplicate_cache_time(Duration::from_secs(385))
            .message_id_fn(gossip_message_id)
            .build()
            .expect("valid gossipsub configuration");

        // discv5 configuration
        let discv5_config = Discv5ConfigBuilder::new()
            .enable_packet_filter()
            .session_cache_capacity(1000)
            .request_timeout(Duration::from_secs(4))
            .request_retries(1)
            .enr_peer_update_min(10)
            .query_parallelism(5)
            .query_timeout(Duration::from_secs(30))
            .query_peer_timeout(Duration::from_secs(2))
            .ip_limit() // limits /24 IP's in buckets.
            .ping_interval(Duration::from_secs(300))
            .build();

        // NOTE: Some of these get overridden by the corresponding CLI default values.
        Config {
            network_dir,
            listen_address: "0.0.0.0".parse().expect("valid ip address"),
            libp2p_port: 9000,
            discovery_port: 9000,
            enr_address: None,
            enr_udp_port: None,
            enr_tcp_port: None,
            target_peers: 50,
            gs_config,
            discv5_config,
            boot_nodes_enr: vec![],
            boot_nodes_multiaddr: vec![],
            libp2p_nodes: vec![],
            client_version: lighthouse_version::version_with_platform(),
            disable_discovery: false,
            topics,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Boxed wrapper implementation.

use std::ops::{Deref, DerefMut};
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use translate::*;

/// Wrapper implementations for Boxed types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_boxed_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
     @free $free_arg:ident $free_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug)]
        pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);

        #[doc(hidden)]
        pub struct MemoryManager;

        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
            #[inline]
            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
                $copy_expr
            }

            #[inline]
            unsafe fn free($free_arg: *mut $ffi_name) {
                $free_expr
            }
        }

        #[doc(hidden)]
        impl $crate::translate::Uninitialized for $name {
            #[inline]
            unsafe fn uninitialized() -> Self {
                $name($crate::boxed::Boxed::uninitialized())
            }
        }

        #[doc(hidden)]
        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = &'a $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0, stash.1)
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name {
            type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none_mut();
                $crate::translate::StashMut(stash.0, stash.1)
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name {
            type Storage = (Vec<Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);

            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
                let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
                v_ptr.push(ptr::null_mut() as *const $ffi_name);

                (v_ptr.as_ptr() as *mut *const $ffi_name, (v, Some(v_ptr)))
            }

            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
                let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

                let v_ptr = unsafe {
                    let v_ptr = glib_ffi::g_malloc0(mem::size_of::<*const $ffi_name>() * t.len() + 1) as *mut *const $ffi_name;

                    for (i, s) in v.iter().enumerate() {
                        ptr::write(v_ptr.offset(i as isize), s.0);
                    }

                    v_ptr
                };

                (v_ptr, (v, None))
            }

            fn to_glib_full_from_slice(t: &[$name]) -> *mut *const $ffi_name {
                unsafe {
                    let v_ptr = glib_ffi::g_malloc0(mem::size_of::<*const $ffi_name>() * t.len() + 1) as *mut *const $ffi_name;

                    for (i, s) in t.iter().enumerate() {
                        ptr::write(v_ptr.offset(i as isize), s.to_glib_full());
                    }

                    v_ptr
                }
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name {
            type Storage = (Vec<Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);

            fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
                let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *const $ffi_name>::to_glib_none_from_slice(t);
                (ptr as *const *const $ffi_name, stash)
            }

            fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
                // Can't have consumer free a *const pointer
                unimplemented!()
            }

            fn to_glib_full_from_slice(_: &[$name]) -> *const *const $ffi_name {
                // Can't have consumer free a *const pointer
                unimplemented!()
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_none(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_full(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_borrow(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
            unsafe fn from_glib_none_num_as_vec(mut ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                if num == 0 || ptr.is_null() {
                    return Vec::new();
                }

                let mut res = Vec::with_capacity(num);
                for _ in 0..num {
                    res.push($crate::translate::from_glib_none(ptr::read(ptr)));
                    ptr = ptr.offset(1);
                }
                res
            }

            unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
                glib_ffi::g_free(ptr as *mut _);
                res
            }

            unsafe fn from_glib_full_num_as_vec(mut ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                if num == 0 || ptr.is_null() {
                    return Vec::new();
                }

                let mut res = Vec::with_capacity(num);
                for _ in 0..num {
                    res.push($crate::translate::from_glib_full(ptr::read(ptr)));
                    ptr = ptr.offset(1);
                }
                glib_ffi::g_free(ptr as *mut _);
                res
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
            unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }

            unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }

            unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }
        }
    }
}

enum AnyBox<T> {
    Native(Box<T>),
    ForeignOwned(*mut T),
    ForeignBorrowed(*mut T),
}

impl<T> fmt::Debug for AnyBox<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::AnyBox::*;
        match *self {
            Native(ref b) => write!(f, "Native({:?})", &**b as *const T),
            ForeignOwned(ptr) => write!(f, "ForeignOwned({:?})", ptr),
            ForeignBorrowed(ptr) => write!(f, "ForeignBorrowed({:?})", ptr),
        }
    }
}

/// Memory management functions for a boxed type.
pub trait BoxedMemoryManager<T>: 'static {
    /// Makes a copy.
    unsafe fn copy(ptr: *const T) -> *mut T;
    /// Frees the object.
    unsafe fn free(ptr: *mut T);
}

/// Encapsulates memory management logic for boxed types.
pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
    inner: AnyBox<T>,
    _dummy: PhantomData<MM>,
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Boxed<T, MM> {
    #[inline]
    pub unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
    #[inline]
    unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtr<'a, *const T> for Boxed<T, MM> {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref b) => &**b as *const T,
            ForeignOwned(p) | ForeignBorrowed(p) => p as *const T,
        };
        Stash(ptr, self)
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtrMut<'a, *mut T> for Boxed<T, MM> {
    type Storage = &'a mut Self;

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref mut b) => &mut **b as *mut T,
            ForeignOwned(p) | ForeignBorrowed(p) => p,
        };
        StashMut(ptr, self)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrNone<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        let ptr = MM::copy(ptr);
        from_glib_full(ptr)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrFull<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignOwned(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrBorrow<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignBorrowed(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            if let AnyBox::ForeignOwned(ptr) = self.inner {
                MM::free(ptr);
            }
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> fmt::Debug for Boxed<T, MM> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Boxed {{ inner: {:?} }}", self.inner)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Clone for Boxed<T, MM> {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            from_glib_none(self.to_glib_none().0 as *mut T)
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Deref for Boxed<T, MM> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            // This is safe because the pointer will remain valid while self is borrowed
            mem::transmute(self.to_glib_none().0)
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> DerefMut for Boxed<T, MM> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            // This is safe because the pointer will remain valid while self is borrowed
            mem::transmute(self.to_glib_none_mut().0)
        }
    }
}
<commit_msg>Implement to_glib_full() for boxed types<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Boxed wrapper implementation.

use std::ops::{Deref, DerefMut};
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use translate::*;

/// Wrapper implementations for Boxed types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_boxed_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
     @free $free_arg:ident $free_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug)]
        pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);

        #[doc(hidden)]
        pub struct MemoryManager;

        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
            #[inline]
            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
                $copy_expr
            }

            #[inline]
            unsafe fn free($free_arg: *mut $ffi_name) {
                $free_expr
            }
        }

        #[doc(hidden)]
        impl $crate::translate::Uninitialized for $name {
            #[inline]
            unsafe fn uninitialized() -> Self {
                $name($crate::boxed::Boxed::uninitialized())
            }
        }

        #[doc(hidden)]
        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = &'a $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *const $ffi_name {
                (&self.0).to_glib_full()
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name {
            type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none_mut();
                $crate::translate::StashMut(stash.0, stash.1)
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name {
            type Storage = (Vec<Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);

            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
                let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
                v_ptr.push(ptr::null_mut() as *const $ffi_name);

                (v_ptr.as_ptr() as *mut *const $ffi_name, (v, Some(v_ptr)))
            }

            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
                let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

                let v_ptr = unsafe {
                    let v_ptr = glib_ffi::g_malloc0(mem::size_of::<*const $ffi_name>() * t.len() + 1) as *mut *const $ffi_name;

                    for (i, s) in v.iter().enumerate() {
                        ptr::write(v_ptr.offset(i as isize), s.0);
                    }

                    v_ptr
                };

                (v_ptr, (v, None))
            }

            fn to_glib_full_from_slice(t: &[$name]) -> *mut *const $ffi_name {
                unsafe {
                    let v_ptr = glib_ffi::g_malloc0(mem::size_of::<*const $ffi_name>() * t.len() + 1) as *mut *const $ffi_name;

                    for (i, s) in t.iter().enumerate() {
                        ptr::write(v_ptr.offset(i as isize), s.to_glib_full());
                    }

                    v_ptr
                }
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name {
            type Storage = (Vec<Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);

            fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
                let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *const $ffi_name>::to_glib_none_from_slice(t);
                (ptr as *const *const $ffi_name, stash)
            }

            fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
                // Can't have consumer free a *const pointer
                unimplemented!()
            }

            fn to_glib_full_from_slice(_: &[$name]) -> *const *const $ffi_name {
                // Can't have consumer free a *const pointer
                unimplemented!()
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_none(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_full(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_borrow(ptr))
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
            unsafe fn from_glib_none_num_as_vec(mut ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                if num == 0 || ptr.is_null() {
                    return Vec::new();
                }

                let mut res = Vec::with_capacity(num);
                for _ in 0..num {
                    res.push($crate::translate::from_glib_none(ptr::read(ptr)));
                    ptr = ptr.offset(1);
                }
                res
            }

            unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
                glib_ffi::g_free(ptr as *mut _);
                res
            }

            unsafe fn from_glib_full_num_as_vec(mut ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
                if num == 0 || ptr.is_null() {
                    return Vec::new();
                }

                let mut res = Vec::with_capacity(num);
                for _ in 0..num {
                    res.push($crate::translate::from_glib_full(ptr::read(ptr)));
                    ptr = ptr.offset(1);
                }
                glib_ffi::g_free(ptr as *mut _);
                res
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
            unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }

            unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }

            unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
                $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
            }
        }
    }
}

enum AnyBox<T> {
    Native(Box<T>),
    ForeignOwned(*mut T),
    ForeignBorrowed(*mut T),
}

impl<T> fmt::Debug for AnyBox<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::AnyBox::*;
        match *self {
            Native(ref b) => write!(f, "Native({:?})", &**b as *const T),
            ForeignOwned(ptr) => write!(f, "ForeignOwned({:?})", ptr),
            ForeignBorrowed(ptr) => write!(f, "ForeignBorrowed({:?})", ptr),
        }
    }
}

/// Memory management functions for a boxed type.
pub trait BoxedMemoryManager<T>: 'static {
    /// Makes a copy.
    unsafe fn copy(ptr: *const T) -> *mut T;
    /// Frees the object.
    unsafe fn free(ptr: *mut T);
}

/// Encapsulates memory management logic for boxed types.
pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
    inner: AnyBox<T>,
    _dummy: PhantomData<MM>,
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Boxed<T, MM> {
    #[inline]
    pub unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
    #[inline]
    unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtr<'a, *const T> for Boxed<T, MM> {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref b) => &**b as *const T,
            ForeignOwned(p) | ForeignBorrowed(p) => p as *const T,
        };
        Stash(ptr, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const T {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref b) => &**b as *const T,
            ForeignOwned(p) | ForeignBorrowed(p) => p as *const T,
        };
        unsafe { MM::copy(ptr) }
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtrMut<'a, *mut T> for Boxed<T, MM> {
    type Storage = &'a mut Self;

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref mut b) => &mut **b as *mut T,
            ForeignOwned(p) | ForeignBorrowed(p) => p,
        };
        StashMut(ptr, self)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrNone<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        let ptr = MM::copy(ptr);
        from_glib_full(ptr)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrFull<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignOwned(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrBorrow<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignBorrowed(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            if let AnyBox::ForeignOwned(ptr) = self.inner {
                MM::free(ptr);
            }
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> fmt::Debug for Boxed<T, MM> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Boxed {{ inner: {:?} }}", self.inner)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Clone for Boxed<T, MM> {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            from_glib_none(self.to_glib_none().0 as *mut T)
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Deref for Boxed<T, MM> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            // This is safe because the pointer will remain valid while self is borrowed
            mem::transmute(self.to_glib_none().0)
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> DerefMut for Boxed<T, MM> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            // This is safe because the pointer will remain valid while self is borrowed
            mem::transmute(self.to_glib_none_mut().0)
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use time::precise_time_s;

use id::Id;
use model::Model;
use object::Object;
use resource::Load;

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 0.1; // 100ms

pub struct CacheBlock<'a, T> where T: 'a {
  data: Vec<(T, PathBuf, (Receiver<Timestamp>, f64))>,
  ids: HashMap<String, Id<'a, T>>,
}

impl<'a, T> CacheBlock<'a, T> {
  pub fn new() -> Self {
    CacheBlock {
      data: Vec::new(),
      ids: HashMap::new(),
    }
  }
}

macro_rules! cache_struct {
  ($l:tt, $($n:ident: $t:ty),*) => {
    pub struct Cache<$l> {
      senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>>,
      $(
        $n: CacheBlock<$l, $t>
      ),*
    }

    impl<$l> Cache<$l> {
      pub fn new() -> Self {
        Cache {
          senders: Arc::new(Mutex::new(HashMap::new())),
          $(
            $n: CacheBlock::new()
          ),*
        }
      }
    }

    $(
      impl<$l> Get<$t> for Cache<$l> {
        type Id = Id<$l, $t>;

        fn get_id(&mut self, name: &str) -> Option<Self::Id> {
          let path_str = format!("data/{}/{}", stringify!($n), name);
          let path = Path::new(&path_str);

          match self.$n.ids.get(name).cloned() {
            id@Some(..) => {
              deb!("cache hit for {}", path_str);
              id
            },
            None => {
              deb!("cache miss for {}", path_str);

              // specific loading
              if path.exists() {
                match <$t as Load>::load(&path) {
                  Ok(resource) => {
                    let path_buf = path.to_owned();

                    // create the id if we have loaded the resource
                    let id: Id<$t> = (self.$n.data.len() as u32).into();

                    // create a channel to notify any update later and register the sender for the
                    // given path
                    let (sx, rx) = channel();
                    {
                      let mut senders = self.senders.lock().unwrap();
                      senders.insert(path_buf.clone(), sx);
                    }

                    // add the resource to the list of loaded ones
                    self.$n.data.push((resource, path_buf.clone(), (rx, precise_time_s())));
                    // cache the resource
                    self.$n.ids.insert(name.to_owned(), id.clone());

                    Some(id)
                  },
                  Err(e) => {
                    err!("unable to load resource from {}: {:?}", path_str, e);
                    None
                  }
                }
              } else { // path doesn’t exist
                err!("ressource at {} cannot be found", path_str);
                None
              }
            }
          }
        }

        fn get_by_id(&mut self, id: Self::Id) -> Option<&$t> {
          // synchronization
          if let Some(data) = self.$n.data.get_mut(*id as usize) {
            match (data.2).0.try_recv() {
              Ok(timestamp) if timestamp - (data.2).1 >= UPDATE_AWAIT_TIME => {
                // reload
                match <$t as Load>::load(&data.1) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    data.0 = new_resource;
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed: {:?}", data.1, e);
                  }
                }
              },
              _ => {}
            }
          } else {
            return None;
          }

          self.$n.data.get(*id as usize).map(|r| &r.0)
        }
      }
    )*
  }
}

pub trait Get<T> where T: Load {
  type Id;

  fn get_id(&mut self, name: &str) -> Option<Self::Id>;
  fn get_by_id(&mut self, id: Self::Id) -> Option<&T>;
  fn get(&mut self, name: &str) -> Option<&T> {
    self.get_id(name).and_then(move |i| self.get_by_id(i))
  }
}

cache_struct!('a,
              models: Model);
<commit_msg>Added some dumb stub code.<commit_after>use std::collections::HashMap;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use time::precise_time_s;

use id::Id;
use model::Model;
use object::Object;
use resource::Load;

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 0.1; // 100ms

pub struct CacheBlock<'a, T> where T: 'a {
  data: Vec<(T, PathBuf, (Receiver<Timestamp>, f64))>,
  ids: HashMap<String, Id<'a, T>>,
}

impl<'a, T> CacheBlock<'a, T> {
  pub fn new() -> Self {
    CacheBlock {
      data: Vec::new(),
      ids: HashMap::new(),
    }
  }
}

macro_rules! cache_struct {
  ($l:tt, $($n:ident: $t:ty),*) => {
    pub struct Cache<$l> {
      senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>>,
      $(
        $n: CacheBlock<$l, $t>
      ),*
    }

    impl<$l> Cache<$l> {
      pub fn new() -> Self {
        let  senders = Arc::new(Mutex::new(HashMap::new()));

        // start watcher thread
        // TODO

        Cache {
          senders: senders,
          $(
            $n: CacheBlock::new()
          ),*
        }
      }
    }

    $(
      impl<$l> Get<$t> for Cache<$l> {
        type Id = Id<$l, $t>;

        fn get_id(&mut self, name: &str) -> Option<Self::Id> {
          let path_str = format!("data/{}/{}", stringify!($n), name);
          let path = Path::new(&path_str);

          match self.$n.ids.get(name).cloned() {
            id@Some(..) => {
              deb!("cache hit for {}", path_str);
              id
            },
            None => {
              deb!("cache miss for {}", path_str);

              // specific loading
              if path.exists() {
                match <$t as Load>::load(&path) {
                  Ok(resource) => {
                    let path_buf = path.to_owned();

                    // create the id if we have loaded the resource
                    let id: Id<$t> = (self.$n.data.len() as u32).into();

                    // create a channel to notify any update later and register the sender for the
                    // given path
                    let (sx, rx) = channel();
                    {
                      let mut senders = self.senders.lock().unwrap();
                      senders.insert(path_buf.clone(), sx);
                    }

                    // add the resource to the list of loaded ones
                    self.$n.data.push((resource, path_buf.clone(), (rx, precise_time_s())));
                    // cache the resource
                    self.$n.ids.insert(name.to_owned(), id.clone());

                    Some(id)
                  },
                  Err(e) => {
                    err!("unable to load resource from {}: {:?}", path_str, e);
                    None
                  }
                }
              } else { // path doesn’t exist
                err!("ressource at {} cannot be found", path_str);
                None
              }
            }
          }
        }

        fn get_by_id(&mut self, id: Self::Id) -> Option<&$t> {
          // synchronization
          if let Some(data) = self.$n.data.get_mut(*id as usize) {
            match (data.2).0.try_recv() {
              Ok(timestamp) if timestamp - (data.2).1 >= UPDATE_AWAIT_TIME => {
                // reload
                match <$t as Load>::load(&data.1) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    data.0 = new_resource;
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed: {:?}", data.1, e);
                  }
                }
              },
              _ => {}
            }
          } else {
            return None;
          }

          self.$n.data.get(*id as usize).map(|r| &r.0)
        }
      }
    )*
  }
}

pub trait Get<T> where T: Load {
  type Id;

  fn get_id(&mut self, name: &str) -> Option<Self::Id>;
  fn get_by_id(&mut self, id: Self::Id) -> Option<&T>;
  fn get(&mut self, name: &str) -> Option<&T> {
    self.get_id(name).and_then(move |i| self.get_by_id(i))
  }
}

cache_struct!('a,
              models: Model);
<|endoftext|>


<commit_before>#![crate_name = "uu_cp"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::Options;
use std::fs;
use std::io::{ErrorKind, Result, Write};
use std::path::Path;
use uucore::fs::{canonicalize, CanonicalizeMode};

#[derive(Clone, Eq, PartialEq)]
pub enum Mode {
    Copy,
    Help,
    Version,
}

static NAME: &'static str = "cp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("v", "version", "output version information and exit");
    opts.optopt("t", "target-directory", "copy all SOURCE arguments into DIRECTORY", "DEST");
    opts.optflag("T", "no-target-directory", "Treat DEST as a regular file and not a directory");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
    };

    let usage = opts.usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");
    let mode = if matches.opt_present("version") {
        Mode::Version
    } else if matches.opt_present("help") {
        Mode::Help
    } else {
        Mode::Copy
    };

    match mode {
        Mode::Copy    => copy(matches),
        Mode::Help    => help(&usage),
        Mode::Version => version(),
    }

    0
}

fn version() {
    println!("{} {}", NAME, VERSION);
}

fn help(usage: &str) {
    let msg = format!("{0} {1}\n\n\
                       Usage: {0} SOURCE DEST\n  \
                         or:  {0} SOURCE... DIRECTORY\n  \
                         or:  {0} -t DIRECTORY SOURCE...\n\
                       \n\
                       {2}", NAME, VERSION, usage);
    println!("{}", msg);
}

fn copy(matches: getopts::Matches) {

    let sources: Vec<String> = if matches.free.is_empty() {
        show_error!("Missing SOURCE or DEST argument. Try --help.");
        panic!()
    } else if !matches.opt_present("target-directory") {
        matches.free[..matches.free.len() - 1].iter().cloned().collect()
    } else {
        matches.free.iter().cloned().collect()
    };
    let dest_str = if matches.opt_present("target-directory") {
        matches.opt_str("target-directory").expect("Option -t/--target-directory requires an argument")
    } else {
        matches.free[matches.free.len() - 1].clone()
    };
    let dest = if matches.free.len() < 2 && !matches.opt_present("target-directory") {
        show_error!("Missing DEST argument. Try --help.");
        panic!()
    } else {
        //the argument to the -t/--target-directory= options
        let path = Path::new(&dest_str);
        if !path.is_dir() && matches.opt_present("target-directory") {
            show_error!("Target {} is not a directory", matches.opt_str("target-directory").unwrap());
            panic!()
        } else {
            path
        }

    };

    assert!(sources.len() >= 1);
    if matches.opt_present("no-target-directory") && dest.is_dir() {
        show_error!("Can't overwrite directory {} with non-directory", dest.display());
        panic!()
    }

    if sources.len() == 1 {
        let source = Path::new(&sources[0]);
        let same_file = paths_refer_to_same_file(source, dest).unwrap_or_else(|err| {
            match err.kind() {
                ErrorKind::NotFound => false,
                _ => {
                    show_error!("{}", err);
                    panic!()
                }
            }
        });

        if same_file {
            show_error!("\"{}\" and \"{}\" are the same file",
                source.display(),
                dest.display());
            panic!();
        }
        let mut full_dest = dest.to_path_buf();
        if dest.is_dir() {
            full_dest.push(source.file_name().unwrap()); //the destination path is the destination
        } // directory + the file name we're copying
        if let Err(err) = fs::copy(source, full_dest) {
            show_error!("{}", err);
            panic!();
        }
    } else {
        if !dest.is_dir() {
            show_error!("TARGET must be a directory");
            panic!();
        }
        for src in &sources {
            let source = Path::new(&src);

            if !source.is_file() {
                show_error!("\"{}\" is not a file", source.display());
                continue;
            }

            let mut full_dest = dest.to_path_buf();

            full_dest.push(source.file_name().unwrap());

            println!("{}", full_dest.display());

            let io_result = fs::copy(source, full_dest);

            if let Err(err) = io_result {
                show_error!("{}", err);
                panic!()
            }
        }
    }
}

pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> Result<bool> {
    // We have to take symlinks and relative paths into account.
    let pathbuf1 = try!(canonicalize(p1, CanonicalizeMode::Normal));
    let pathbuf2 = try!(canonicalize(p2, CanonicalizeMode::Normal));

    Ok(pathbuf1 == pathbuf2)
}
<commit_msg>cp: added -v/--verbose flag<commit_after>#![crate_name = "uu_cp"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::Options;
use std::fs;
use std::io::{ErrorKind, Result, Write};
use std::path::Path;
use uucore::fs::{canonicalize, CanonicalizeMode};

#[derive(Clone, Eq, PartialEq)]
pub enum Mode {
    Copy,
    Help,
    Version,
}

static NAME: &'static str = "cp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");
    opts.optopt("t", "target-directory", "copy all SOURCE arguments into DIRECTORY", "DEST");
    opts.optflag("T", "no-target-directory", "Treat DEST as a regular file and not a directory");
    opts.optflag("v", "verbose", "explicitly state what is being done");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
    };
    let usage = opts.usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");
    let mode = if matches.opt_present("version") {
        Mode::Version
    } else if matches.opt_present("help") {
        Mode::Help
    } else {
        Mode::Copy
    };

    match mode {
        Mode::Copy    => copy(matches),
        Mode::Help    => help(&usage),
        Mode::Version => version(),
    }

    0
}

fn version() {
    println!("{} {}", NAME, VERSION);
}

fn help(usage: &str) {
    let msg = format!("{0} {1}\n\n\
                       Usage: {0} SOURCE DEST\n  \
                         or:  {0} SOURCE... DIRECTORY\n  \
                         or:  {0} -t DIRECTORY SOURCE...\n\
                       \n\
                       {2}", NAME, VERSION, usage);
    println!("{}", msg);
}

fn copy(matches: getopts::Matches) {
    let verbose = matches.opt_present("verbose");
    let sources: Vec<String> = if matches.free.is_empty() {
        show_error!("Missing SOURCE or DEST argument. Try --help.");
        panic!()
    } else if !matches.opt_present("target-directory") {
        matches.free[..matches.free.len() - 1].iter().cloned().collect()
    } else {
        matches.free.iter().cloned().collect()
    };
    let dest_str = if matches.opt_present("target-directory") {
        matches.opt_str("target-directory").expect("Option -t/--target-directory requires an argument")
    } else {
        matches.free[matches.free.len() - 1].clone()
    };
    let dest = if matches.free.len() < 2 && !matches.opt_present("target-directory") {
        show_error!("Missing DEST argument. Try --help.");
        panic!()
    } else {
        //the argument to the -t/--target-directory= options
        let path = Path::new(&dest_str);
        if !path.is_dir() && matches.opt_present("target-directory") {
            show_error!("Target {} is not a directory", matches.opt_str("target-directory").unwrap());
            panic!()
        } else {
            path
        }

    };

    assert!(sources.len() >= 1);
    if matches.opt_present("no-target-directory") && dest.is_dir() {
        show_error!("Can't overwrite directory {} with non-directory", dest.display());
        panic!()
    }

    if sources.len() == 1 {
        let source = Path::new(&sources[0]);
        let same_file = paths_refer_to_same_file(source, dest).unwrap_or_else(|err| {
            match err.kind() {
                ErrorKind::NotFound => false,
                _ => {
                    show_error!("{}", err);
                    panic!()
                }
            }
        });

        if same_file {
            show_error!("\"{}\" and \"{}\" are the same file",
                source.display(),
                dest.display());
            panic!();
        }
        let mut full_dest = dest.to_path_buf();
        if dest.is_dir() {
            full_dest.push(source.file_name().unwrap()); //the destination path is the destination
        } // directory + the file name we're copying
        if verbose {
            println!("{} -> {}", source.display(), full_dest.display());
        }
        if let Err(err) = fs::copy(source, full_dest) {
            show_error!("{}", err);
            panic!();
        }
    } else {
        if !dest.is_dir() {
            show_error!("TARGET must be a directory");
            panic!();
        }
        for src in &sources {
            let source = Path::new(&src);

            if !source.is_file() {
                show_error!("\"{}\" is not a file", source.display());
                continue;
            }

            let mut full_dest = dest.to_path_buf();

            full_dest.push(source.file_name().unwrap());

            if verbose {
                println!("{} -> {}", source.display(), full_dest.display());
            }

            let io_result = fs::copy(source, full_dest);

            if let Err(err) = io_result {
                show_error!("{}", err);
                panic!()
            }
        }
    }
}

pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> Result<bool> {
    // We have to take symlinks and relative paths into account.
    let pathbuf1 = try!(canonicalize(p1, CanonicalizeMode::Normal));
    let pathbuf2 = try!(canonicalize(p2, CanonicalizeMode::Normal));

    Ok(pathbuf1 == pathbuf2)
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let ts = Timespec::new(0, 0);
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.as_string().unwrap().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };

    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: uint, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        let bytes = "Hello world!\n".as_bytes();
        reply.data(bytes);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day 15&16)");
    let data = json!({
        "foo": "bar",
        "answer": "42",
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>Better timestamps and file sizes.<commit_after>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.to_pretty_str().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };

    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: uint, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        let bytes = "Hello world!\n".as_bytes();
        reply.data(bytes);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day 15&16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>