<commit_before>use ide_db::helpers::mod_path_to_ast;
use ide_db::imports_locator;
use itertools::Itertools;
use syntax::{
    ast::{self, make, AstNode},
    Direction,
    SyntaxKind::{IDENT, WHITESPACE},
    TextSize,
};

use crate::{
    assist_context::{AssistBuilder, AssistContext, Assists},
    utils::{
        add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods,
    },
    AssistId, AssistKind,
};

// Assist: replace_derive_with_manual_impl
//
// Converts a `derive` impl into a manual one.
//
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Deb$0ug, Display)]
// struct S;
// ```
// ->
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Display)]
// struct S;
//
// impl Debug for S {
//     fn fmt(&self, f: &mut Formatter) -> Result<()> {
//         ${0:todo!()}
//     }
// }
// ```
pub(crate) fn replace_derive_with_manual_impl(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let attr = ctx.find_node_at_offset::<ast::Attr>()?;

    let has_derive = attr
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .find_map(syntax::NodeOrToken::into_token)
        .filter(|t| t.text() == "derive")
        .is_some();
    if !has_derive {
        return None;
    }

    let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
    let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));

    let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?;
    let insert_pos = annotated_name.syntax().parent()?.text_range().end();

    let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
    let current_crate = current_module.krate();

    let found_traits = imports_locator::find_exact_imports(
        &ctx.sema,
        current_crate,
        trait_token.text().to_string(),
    )
    .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
        either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
        _ => None,
    })
    .flat_map(|trait_| {
        current_module
            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
            .as_ref()
            .map(mod_path_to_ast)
            .zip(Some(trait_))
    });

    let mut no_traits_found = true;
    for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
        add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?;
    }
    if no_traits_found {
        add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?;
    }
    Some(())
}

fn add_assist(
    acc: &mut Assists,
    ctx: &AssistContext,
    attr: &ast::Attr,
    trait_path: &ast::Path,
    trait_: Option<hir::Trait>,
    annotated_name: &ast::Name,
    insert_pos: TextSize,
) -> Option<()> {
    let target = attr.syntax().text_range();
    let input = attr.token_tree()?;
    let label = format!("Convert to manual  `impl {} for {}`", trait_path, annotated_name);
    let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;

    acc.add(
        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
        label,
        target,
        |builder| {
            let impl_def_with_items =
                impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
            update_attribute(builder, &input, &trait_name, &attr);
            match (ctx.config.snippet_cap, impl_def_with_items) {
                (None, _) => builder.insert(
                    insert_pos,
                    format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name),
                ),
                (Some(cap), None) => builder.insert_snippet(
                    cap,
                    insert_pos,
                    format!("\n\nimpl {} for {} {{\n    $0\n}}", trait_path, annotated_name),
                ),
                (Some(cap), Some((impl_def, first_assoc_item))) => {
                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
                    let placeholder;
                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                        {
                            if m.syntax().text() == "todo!()" {
                                placeholder = m;
                                cursor = Cursor::Replace(placeholder.syntax());
                            }
                        }
                    }

                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
                    )
                }
            };
        },
    )
}

fn impl_def_from_trait(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    annotated_name: &ast::Name,
    trait_: Option<hir::Trait>,
    trait_path: &ast::Path,
) -> Option<(ast::Impl, ast::AssocItem)> {
    let trait_ = trait_?;
    let target_scope = sema.scope(annotated_name.syntax());
    let trait_items = filter_assoc_items(sema.db, &trait_.items(sema.db), DefaultMethods::No);
    if trait_items.is_empty() {
        return None;
    }
    let impl_def = make::impl_trait(
        trait_path.clone(),
        make::path_unqualified(make::path_segment(make::name_ref(annotated_name.text()))),
    );
    let (impl_def, first_assoc_item) =
        add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
    Some((impl_def, first_assoc_item))
}

fn update_attribute(
    builder: &mut AssistBuilder,
    input: &ast::TokenTree,
    trait_name: &ast::NameRef,
    attr: &ast::Attr,
) {
    let new_attr_input = input
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
        .filter(|t| t != trait_name.text())
        .collect::<Vec<_>>();
    let has_more_derives = !new_attr_input.is_empty();

    if has_more_derives {
        let new_attr_input = format!("({})", new_attr_input.iter().format(", "));
        builder.replace(input.syntax().text_range(), new_attr_input);
    } else {
        let attr_range = attr.syntax().text_range();
        builder.delete(attr_range);

        if let Some(line_break_range) = attr
            .syntax()
            .next_sibling_or_token()
            .filter(|t| t.kind() == WHITESPACE)
            .map(|t| t.text_range())
        {
            builder.delete(line_break_range);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_custom_impl_debug() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
",
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

struct Foo {
    bar: String,
}

impl fmt::Debug for Foo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ${0:todo!()}
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_all() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

#[derive($0Bar)]
struct Foo {
    bar: String,
}
",
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

struct Foo {
    bar: String,
}

impl foo::Bar for Foo {
    $0type Qux;

    const Baz: usize = 42;

    const Fez: usize;

    fn foo() {
        todo!()
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_for_unique_input() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
            ",
            "
struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_for_with_visibility_modifier() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debug$0)]
pub struct Foo {
    bar: String,
}
            ",
            "
pub struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_when_multiple_inputs() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Display, Debug$0, Serialize)]
struct Foo {}
            ",
            "
#[derive(Display, Serialize)]
struct Foo {}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn test_ignore_derive_macro_without_input() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive($0)]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_cursor_on_param() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive$0(Debug)]
struct Foo {}
            ",
        );

        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive(Debug)$0]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_not_derive() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[allow(non_camel_$0case_types)]
struct Foo {}
            ",
        )
    }
}
<commit_msg>use generate_impl_text in replace_derive_with_manual_impl<commit_after>use ide_db::helpers::mod_path_to_ast;
use ide_db::imports_locator;
use itertools::Itertools;
use syntax::{SyntaxKind::{IDENT, WHITESPACE}, TextSize, ast::{self, AstNode, NameOwner, make}};

use crate::{AssistId, AssistKind, assist_context::{AssistBuilder, AssistContext, Assists}, utils::{Cursor, DefaultMethods, add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text, render_snippet}};

// Assist: replace_derive_with_manual_impl
//
// Converts a `derive` impl into a manual one.
//
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Deb$0ug, Display)]
// struct S;
// ```
// ->
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Display)]
// struct S;
//
// impl Debug for S {
//     fn fmt(&self, f: &mut Formatter) -> Result<()> {
//         ${0:todo!()}
//     }
// }
// ```
pub(crate) fn replace_derive_with_manual_impl(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let attr = ctx.find_node_at_offset::<ast::Attr>()?;

    let has_derive = attr
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .find_map(syntax::NodeOrToken::into_token)
        .filter(|t| t.text() == "derive")
        .is_some();
    if !has_derive {
        return None;
    }

    let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
    let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));

    let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
    let annotated_name = adt.name()?;
    let insert_pos = adt.syntax().text_range().end();

    let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
    let current_crate = current_module.krate();

    let found_traits = imports_locator::find_exact_imports(
        &ctx.sema,
        current_crate,
        trait_token.text().to_string(),
    )
    .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
        either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
        _ => None,
    })
    .flat_map(|trait_| {
        current_module
            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
            .as_ref()
            .map(mod_path_to_ast)
            .zip(Some(trait_))
    });

    let mut no_traits_found = true;
    for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
        add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?;
    }
    if no_traits_found {
        add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?;
    }
    Some(())
}

fn add_assist(
    acc: &mut Assists,
    ctx: &AssistContext,
    attr: &ast::Attr,
    trait_path: &ast::Path,
    trait_: Option<hir::Trait>,
    adt: &ast::Adt,
    annotated_name: &ast::Name,
    insert_pos: TextSize,
) -> Option<()> {
    let target = attr.syntax().text_range();
    let input = attr.token_tree()?;
    let label = format!("Convert to manual  `impl {} for {}`", trait_path, annotated_name);
    let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;

    acc.add(
        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
        label,
        target,
        |builder| {
            let impl_def_with_items =
                impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
            update_attribute(builder, &input, &trait_name, &attr);
            let trait_path = format!("{}", trait_path);
            match (ctx.config.snippet_cap, impl_def_with_items) {
                (None, _) => builder.insert(
                    insert_pos,
                    generate_trait_impl_text(adt, &trait_path, ""),
                ),
                (Some(cap), None) => builder.insert_snippet(
                    cap,
                    insert_pos,
                    generate_trait_impl_text(adt, &trait_path, "    $0"),
                ),
                (Some(cap), Some((impl_def, first_assoc_item))) => {
                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
                    let placeholder;
                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                        {
                            if m.syntax().text() == "todo!()" {
                                placeholder = m;
                                cursor = Cursor::Replace(placeholder.syntax());
                            }
                        }
                    }

                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
                    )
                }
            };
        },
    )
}

fn impl_def_from_trait(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    annotated_name: &ast::Name,
    trait_: Option<hir::Trait>,
    trait_path: &ast::Path,
) -> Option<(ast::Impl, ast::AssocItem)> {
    let trait_ = trait_?;
    let target_scope = sema.scope(annotated_name.syntax());
    let trait_items = filter_assoc_items(sema.db, &trait_.items(sema.db), DefaultMethods::No);
    if trait_items.is_empty() {
        return None;
    }
    let impl_def = make::impl_trait(
        trait_path.clone(),
        make::path_unqualified(make::path_segment(make::name_ref(annotated_name.text()))),
    );
    let (impl_def, first_assoc_item) =
        add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
    Some((impl_def, first_assoc_item))
}

fn update_attribute(
    builder: &mut AssistBuilder,
    input: &ast::TokenTree,
    trait_name: &ast::NameRef,
    attr: &ast::Attr,
) {
    let new_attr_input = input
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
        .filter(|t| t != trait_name.text())
        .collect::<Vec<_>>();
    let has_more_derives = !new_attr_input.is_empty();

    if has_more_derives {
        let new_attr_input = format!("({})", new_attr_input.iter().format(", "));
        builder.replace(input.syntax().text_range(), new_attr_input);
    } else {
        let attr_range = attr.syntax().text_range();
        builder.delete(attr_range);

        if let Some(line_break_range) = attr
            .syntax()
            .next_sibling_or_token()
            .filter(|t| t.kind() == WHITESPACE)
            .map(|t| t.text_range())
        {
            builder.delete(line_break_range);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_custom_impl_debug() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
",
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

struct Foo {
    bar: String,
}

impl fmt::Debug for Foo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ${0:todo!()}
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_all() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

#[derive($0Bar)]
struct Foo {
    bar: String,
}
",
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

struct Foo {
    bar: String,
}

impl foo::Bar for Foo {
    $0type Qux;

    const Baz: usize = 42;

    const Fez: usize;

    fn foo() {
        todo!()
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_for_unique_input() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
            ",
            "
struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_for_with_visibility_modifier() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debug$0)]
pub struct Foo {
    bar: String,
}
            ",
            "
pub struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_when_multiple_inputs() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Display, Debug$0, Serialize)]
struct Foo {}
            ",
            "
#[derive(Display, Serialize)]
struct Foo {}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn test_ignore_derive_macro_without_input() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive($0)]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_cursor_on_param() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive$0(Debug)]
struct Foo {}
            ",
        );

        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive(Debug)$0]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_not_derive() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[allow(non_camel_$0case_types)]
struct Foo {}
            ",
        )
    }
}
<|endoftext|>


<commit_before>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

#![feature(std_misc)] // hash_map::Entry
#![feature(path)]
#![feature(fs)]
#![feature(io)]

use std::path::Path;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;

#[derive(Clone,Debug)]
struct ProcessRecord {
    name: String,
    pid: i32,
    ppid: i32,
}

#[derive(Clone,Debug)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[derive(Clone,Debug)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<i32> = None;
    let mut ppid : Option<i32> = None;
    let mut name : Option<String> = None;

    let mut reader = std::io::BufReader::new(File::open(status_path).unwrap());
    loop {
        let mut linebuf = String::new();
        match reader.read_line(&mut linebuf) {
            Ok(_) => {
                if linebuf.is_empty() {
                    break;
                }
                let parts : Vec<&str> = linebuf[..].splitn(2, ':').collect();
                if parts.len() == 2 {
                    let key = parts[0].trim();
                    let value = parts[1].trim();
                    match key {
                        "Name" => name = Some(value.to_string()),
                        "Pid" => pid = value.parse().ok(),
                        "PPid" => ppid = value.parse().ok(),
                        _ => (),
                    }
                }
            },
            Err(_) => break,
        }
    }
    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = fs::read_dir(&proc_directory).unwrap();
    proc_directory_contents.filter_map(|entry| {
        let entry_path = entry.unwrap().path();
        if entry_path.is_dir() {
            let status_path = entry_path.join("status");
            if status_path.exists() {
                return get_process_record(&status_path)
            }
        }
        None
    }).collect()
}

fn populate_node_helper(node: &mut ProcessTreeNode, pid_map: &HashMap<i32, &ProcessRecord>, ppid_map: &HashMap<i32, Vec<i32>>) {
    let pid = node.record.pid; // avoid binding node as immutable in closure
    let child_nodes = &mut node.children;
    match ppid_map.get(&pid) {
        Some(children) => {
            child_nodes.extend(children.iter().map(|child_pid| {
                let record = pid_map[*child_pid];
                let mut child = ProcessTreeNode::new(record);
                populate_node_helper(&mut child, pid_map, ppid_map);
                child
            }));
        },
        None => {},
    }
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // O(n): build a mapping of pids to vectors of children.  That is, each
    // key is a pid and its value is a vector of the whose parent pid is the key
    let mut ppid_map : HashMap<i32, Vec<i32>> = HashMap::new();
    let mut pid_map : HashMap<i32, &ProcessRecord> = HashMap::new();
    for record in records.iter() {
        // entry returns either a vacant or occupied entry.  If vacant,
        // we insert a new vector with this records pid.  If occupied,
        // we push this record's pid onto the vec
        pid_map.insert(record.pid, record);
        match ppid_map.entry(record.ppid) {
            Vacant(entry) => { entry.insert(vec![record.pid]); },
            Occupied(mut entry) => { entry.get_mut().push(record.pid); },
        };
    }

    // With the data structures built, it is off to the races
    populate_node_helper(node, &pid_map, &ppid_map);
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord {
                name: "/".to_string(),
                pid: 0,
                ppid: -1
            })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : i32) {
    // print indentation
    for _ in (0..indent_level) {
        print!("  ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<commit_msg>rustup: update to run on the latest rust nightlies<commit_after>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

#![feature(path_ext)]

use std::path::Path;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;

#[derive(Clone,Debug)]
struct ProcessRecord {
    name: String,
    pid: i32,
    ppid: i32,
}

#[derive(Clone,Debug)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[derive(Clone,Debug)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<i32> = None;
    let mut ppid : Option<i32> = None;
    let mut name : Option<String> = None;

    let mut reader = std::io::BufReader::new(File::open(status_path).unwrap());
    loop {
        let mut linebuf = String::new();
        match reader.read_line(&mut linebuf) {
            Ok(_) => {
                if linebuf.is_empty() {
                    break;
                }
                let parts : Vec<&str> = linebuf[..].splitn(2, ':').collect();
                if parts.len() == 2 {
                    let key = parts[0].trim();
                    let value = parts[1].trim();
                    match key {
                        "Name" => name = Some(value.to_string()),
                        "Pid" => pid = value.parse().ok(),
                        "PPid" => ppid = value.parse().ok(),
                        _ => (),
                    }
                }
            },
            Err(_) => break,
        }
    }
    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = fs::read_dir(&proc_directory).unwrap();
    proc_directory_contents.filter_map(|entry| {
        let entry_path = entry.unwrap().path();
        if entry_path.is_dir() {
            let status_path = entry_path.join("status");
            if status_path.exists() {
                return get_process_record(&status_path)
            }
        }
        None
    }).collect()
}

fn populate_node_helper(node: &mut ProcessTreeNode, pid_map: &HashMap<i32, &ProcessRecord>, ppid_map: &HashMap<i32, Vec<i32>>) {
    let pid = node.record.pid; // avoid binding node as immutable in closure
    let child_nodes = &mut node.children;
    match ppid_map.get(&pid) {
        Some(children) => {
            child_nodes.extend(children.iter().map(|child_pid| {
                let record = pid_map[child_pid];
                let mut child = ProcessTreeNode::new(record);
                populate_node_helper(&mut child, pid_map, ppid_map);
                child
            }));
        },
        None => {},
    }
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // O(n): build a mapping of pids to vectors of children.  That is, each
    // key is a pid and its value is a vector of the whose parent pid is the key
    let mut ppid_map : HashMap<i32, Vec<i32>> = HashMap::new();
    let mut pid_map : HashMap<i32, &ProcessRecord> = HashMap::new();
    for record in records.iter() {
        // entry returns either a vacant or occupied entry.  If vacant,
        // we insert a new vector with this records pid.  If occupied,
        // we push this record's pid onto the vec
        pid_map.insert(record.pid, record);
        match ppid_map.entry(record.ppid) {
            Vacant(entry) => { entry.insert(vec![record.pid]); },
            Occupied(mut entry) => { entry.get_mut().push(record.pid); },
        };
    }

    // With the data structures built, it is off to the races
    populate_node_helper(node, &pid_map, &ppid_map);
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord {
                name: "/".to_string(),
                pid: 0,
                ppid: -1
            })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : i32) {
    // print indentation
    for _ in (0..indent_level) {
        print!("  ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
};
use crevice::std430::{AsStd430, Std430};

/// Array of instances for fast rendering.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    capacity: u32,
    len: u32,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances.
    pub fn new(gfx: &GraphicsContext, capacity: u32) -> Self {
        let buffer = ArcBuffer::new(gfx.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std430_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        InstanceArray {
            buffer,
            capacity,
            len: 0,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    ///
    /// Prefer this over `push` where possible.
    #[allow(unsafe_code)]
    pub fn set<I>(&mut self, gfx: &GraphicsContext, instances: I)
    where
        I: IntoIterator<Item = DrawParam>,
        I::IntoIter: ExactSizeIterator,
    {
        let instances = instances.into_iter();

        assert!(
            instances.len() <= self.capacity as usize,
            "exceeding instance array capacity"
        );

        let instances = instances
            .map(|param| DrawUniforms::from_param(param, glam::Vec2::ONE.into()))
            .collect::<Vec<_>>();

        self.len = instances.len() as u32;
        gfx.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std430_size_static(),
            )
        });
    }

    /// Pushes a new instance onto the end.
    ///
    /// Prefer `set` where bulk instances needs to be set.
    pub fn push(&mut self, gfx: &GraphicsContext, instance: DrawParam) {
        assert!(
            self.len < self.capacity,
            "exceeding instance array capacity"
        );

        let instance = DrawUniforms::from_param(instance, glam::Vec2::ONE.into());
        gfx.queue.write_buffer(
            &self.buffer,
            self.len as u64 * DrawUniforms::std430_size_static() as u64,
            instance.as_std430().as_bytes(),
        );
        self.len += 1;
    }

    /// Updates an existing instance at a given index.
    pub fn update(&mut self, gfx: &GraphicsContext, index: u32, instance: DrawParam) {
        assert!(index < self.len);

        let instance = DrawUniforms::from_param(instance, glam::Vec2::ONE.into());
        gfx.queue.write_buffer(
            &self.buffer,
            index as u64 * DrawUniforms::std430_size_static() as u64,
            instance.as_std430().as_bytes(),
        );
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len = 0;
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline(always)]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    /// Returns the number of instances.
    #[inline(always)]
    pub fn len(&self) -> usize {
        self.len as usize
    }
}
<commit_msg>clarify instancearray doc<commit_after>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
};
use crevice::std430::{AsStd430, Std430};

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    capacity: u32,
    len: u32,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances.
    pub fn new(gfx: &GraphicsContext, capacity: u32) -> Self {
        let buffer = ArcBuffer::new(gfx.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std430_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        InstanceArray {
            buffer,
            capacity,
            len: 0,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    ///
    /// Prefer this over `push` where possible.
    #[allow(unsafe_code)]
    pub fn set<I>(&mut self, gfx: &GraphicsContext, instances: I)
    where
        I: IntoIterator<Item = DrawParam>,
        I::IntoIter: ExactSizeIterator,
    {
        let instances = instances.into_iter();

        assert!(
            instances.len() <= self.capacity as usize,
            "exceeding instance array capacity"
        );

        let instances = instances
            .map(|param| DrawUniforms::from_param(param, glam::Vec2::ONE.into()))
            .collect::<Vec<_>>();

        self.len = instances.len() as u32;
        gfx.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std430_size_static(),
            )
        });
    }

    /// Pushes a new instance onto the end.
    ///
    /// Prefer `set` where bulk instances needs to be set.
    pub fn push(&mut self, gfx: &GraphicsContext, instance: DrawParam) {
        assert!(
            self.len < self.capacity,
            "exceeding instance array capacity"
        );

        let instance = DrawUniforms::from_param(instance, glam::Vec2::ONE.into());
        gfx.queue.write_buffer(
            &self.buffer,
            self.len as u64 * DrawUniforms::std430_size_static() as u64,
            instance.as_std430().as_bytes(),
        );
        self.len += 1;
    }

    /// Updates an existing instance at a given index.
    pub fn update(&mut self, gfx: &GraphicsContext, index: u32, instance: DrawParam) {
        assert!(index < self.len);

        let instance = DrawUniforms::from_param(instance, glam::Vec2::ONE.into());
        gfx.queue.write_buffer(
            &self.buffer,
            index as u64 * DrawUniforms::std430_size_static() as u64,
            instance.as_std430().as_bytes(),
        );
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len = 0;
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline(always)]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    /// Returns the number of instances.
    #[inline(always)]
    pub fn len(&self) -> usize {
        self.len as usize
    }
}
<|endoftext|>


<commit_before>use json::{self, JsonValue};
use std::convert::TryFrom;
use std::str::FromStr;

// ["t","714109",1,"0.12900000","1.03377186",1504163835]
#[derive(Debug)]
pub struct TradeRecord {
  pub id: u64,
  pub tid: String,
  pub rate: f64,
  pub amount: f64,
}

// ["o",1,"0.12774723","0.00000000"]
#[derive(Debug)]
pub struct BookRecord {
  pub rate: f64,
  pub amount: f64,
}

#[derive(Debug)]
pub enum RecordUpdate {
  SellTotal(BookRecord),
  BuyTotal(BookRecord),
  Sell(TradeRecord),
  Buy(TradeRecord)
}

// book update message
// ex: [189,4811375,[["o",1,"0.12774723","0.00000000"],["t","714109",1,"0.12900000","1.03377186",1504163835]]]
#[derive(Debug)]
pub struct BookUpdate {
  pub book_id: u64,
  pub record_id: u64,
  pub records: Vec<RecordUpdate>
}

/**
 * internal trait for serde_json::Value evaluation and conversion
**/
trait Expect<T> {
  type Error;
  fn expect(&self, msg: &str) -> Result<T, Self::Error>;
}

impl Expect<f64> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<f64, Self::Error> {
    let err = || format!("{}: expected float got {}", msg, self);
    if self.is_string() {
      self.as_str().ok_or_else(err)?.parse::<f64>().map_err(|err| err.to_string())
    } else {
      self.as_f64().ok_or_else(err)
    }
  }
}

impl Expect<u64> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<u64, Self::Error> {
    let err = || format!("{}: expected float got {}", msg, self);
    if self.is_string() {
      self.as_str().ok_or_else(err)?.parse::<u64>().map_err(|err| err.to_string())
    } else {
      self.as_u64().ok_or_else(err)
    }
  }
}

impl Expect<String> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<String, Self::Error> {
    let err = || format!("{}: expected string got {}", msg, self);
    Ok(String::from(self.as_str().ok_or_else(err)?))
  }
}

/**
 * TradeRecord conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["t","714109",1,"0.12900000","1.03377186",1504163835]"#) {
 *     serde_json::Array(vec) => vec,
 *     _ => Err(())
 *  };
 *  let records:: TradeRecord = TradeRecord::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for TradeRecord {
  type Error = String;
  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 6 {
      return Err(format!("trade record does not have 6 items {:?}", v));
    }

    let id: u64 = v[5].expect("trade record id")?;
    let tid: String = v[1].expect("trade record tid")?;
    let rate: f64 = v[3].expect("trade record rate")?;
    let amount: f64 = v[4].expect("trade record amount")?;

    Ok(Self {id, tid, rate, amount})
  }
}

/**
 * BookRecord conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["o",0,"0.12900000","1.03377186"]"#) {
 *     serde_json::Array(vec) => vec,
 *     _ => Err(())
 *  };
 *  let records:: BookRecord = BookRecord::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for BookRecord {
  type Error = String;
  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 4 {
      return Err(format!("book record does not have 4 items {:?}", v));
    }

    let rate: f64 = v[2].expect("book record rate")?;
    let amount: f64 = v[3].expect("book record amount")?;

    Ok(Self {rate, amount})
  }
}

/**
 * RecordUpdate enum conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["o",0,"0.12900000","1.03377186"]"#);
 *  let records:: RecordUpdate = RecordUpdate::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for RecordUpdate {
  type Error = String;

  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    let err = |msg| Err(format!("book update record {} {:?}", msg, v));
    if v.len() < 3 {
      return err("has less than 3 items");
    }

    match v[0].as_str() {
      Some("o") => {
        let direction: u64 = v[1].expect("book record direction")?;
        let record = BookRecord::try_from(v)?;
        match direction {
          0 => Ok(RecordUpdate::SellTotal(record)),
          1 => Ok(RecordUpdate::BuyTotal(record)),
          _ => err("has unknown dir")
        }
      },
      Some("t") => {
        let direction: u64 = v[2].expect("book record direction")?;
        let record = TradeRecord::try_from(v)?;
        match direction {
          0 => Ok(RecordUpdate::Sell(record)),
          1 => Ok(RecordUpdate::Buy(record)),
          _ => err("has unknown dir")
        }
      },
      _ => err("has unknown type")
    }
  }
}

/**
 * BookUpdate conversion traits
 * use:
 *  let update:: BookUpdate = BookUpdate::from_str(
 *    r#"[189,4811375,[["o",1,"0.12774723","0.00000000"],["t","714109",1,"0.12900000","1.03377186",1504163835]]]"#
 *  )
 **/

impl FromStr for BookUpdate {
  type Err = String;
  fn from_str(order: &str) -> Result<Self, Self::Err> {
    let v = json::parse(order).map_err(|err| err.to_string())?;
    Ok(BookUpdate::try_from(v)?)
  }
}

impl TryFrom<JsonValue> for BookUpdate {
  type Error = String;
  fn try_from(v: JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 3 {
      return Err(format!("book update is not triple {:?}", v));
    }
    if !v[2].is_array() {
      return Err(format!("book update records: expected array got {:?}", v));
    }

    let book_id: u64 = v[0].expect("book update book_id")?;
    let record_id: u64 = v[1].expect("book update record_id")?;
    let mut records: Vec<RecordUpdate> = vec![];
    for record in v[2].members() {
      records.push(RecordUpdate::try_from(record)?)
    };

    Ok(Self { book_id, record_id, records })
  }
}

#[cfg(test)]
mod tests {
  use super::BookUpdate;
  use std::str::FromStr;
  use test::Bencher;
  use json;

  #[test]
  fn json_deserialize_order_update() {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Err(error) => panic!("failed to process json {}", error),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err1() {
    let order = r#"[189,4811424,[["o",1,"bad","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err2() {
    let order = r#"[189,4811424]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err3() {
    let order = r#"[189,4811424,[["f",1,"0.120000","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err4() {
    let order = r#"[189,4811424,[["o",3,"0.120000","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[bench]
  fn json_read_order_updates(b: &mut Bencher) {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    b.iter(|| BookUpdate::from_str(&order));
  }

  #[bench]
  fn json_read_order_updates_json(b: &mut Bencher) {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    b.iter(|| json::parse(order));
  }
}<commit_msg>derive clone with update struct<commit_after>use json::{self, JsonValue};
use std::convert::TryFrom;
use std::str::FromStr;

// ["t","714109",1,"0.12900000","1.03377186",1504163835]
#[derive(Debug, Clone)]
pub struct TradeRecord {
  pub id: u64,
  pub tid: String,
  pub rate: f64,
  pub amount: f64,
}

// ["o",1,"0.12774723","0.00000000"]
#[derive(Debug, Clone)]
pub struct BookRecord {
  pub rate: f64,
  pub amount: f64,
}

#[derive(Debug, Clone)]
pub enum RecordUpdate {
  SellTotal(BookRecord),
  BuyTotal(BookRecord),
  Sell(TradeRecord),
  Buy(TradeRecord)
}

// book update message
// ex: [189,4811375,[["o",1,"0.12774723","0.00000000"],["t","714109",1,"0.12900000","1.03377186",1504163835]]]
#[derive(Debug, Clone)]
pub struct BookUpdate {
  pub book_id: u64,
  pub record_id: u64,
  pub records: Vec<RecordUpdate>
}

/**
 * internal trait for serde_json::Value evaluation and conversion
**/
trait Expect<T> {
  type Error;
  fn expect(&self, msg: &str) -> Result<T, Self::Error>;
}

impl Expect<f64> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<f64, Self::Error> {
    let err = || format!("{}: expected float got {}", msg, self);
    if self.is_string() {
      self.as_str().ok_or_else(err)?.parse::<f64>().map_err(|err| err.to_string())
    } else {
      self.as_f64().ok_or_else(err)
    }
  }
}

impl Expect<u64> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<u64, Self::Error> {
    let err = || format!("{}: expected float got {}", msg, self);
    if self.is_string() {
      self.as_str().ok_or_else(err)?.parse::<u64>().map_err(|err| err.to_string())
    } else {
      self.as_u64().ok_or_else(err)
    }
  }
}

impl Expect<String> for JsonValue {
  type Error = String;
  fn expect(&self, msg: &str) -> Result<String, Self::Error> {
    let err = || format!("{}: expected string got {}", msg, self);
    Ok(String::from(self.as_str().ok_or_else(err)?))
  }
}

/**
 * TradeRecord conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["t","714109",1,"0.12900000","1.03377186",1504163835]"#) {
 *     serde_json::Array(vec) => vec,
 *     _ => Err(())
 *  };
 *  let records:: TradeRecord = TradeRecord::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for TradeRecord {
  type Error = String;
  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 6 {
      return Err(format!("trade record does not have 6 items {:?}", v));
    }

    let id: u64 = v[5].expect("trade record id")?;
    let tid: String = v[1].expect("trade record tid")?;
    let rate: f64 = v[3].expect("trade record rate")?;
    let amount: f64 = v[4].expect("trade record amount")?;

    Ok(Self {id, tid, rate, amount})
  }
}

/**
 * BookRecord conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["o",0,"0.12900000","1.03377186"]"#) {
 *     serde_json::Array(vec) => vec,
 *     _ => Err(())
 *  };
 *  let records:: BookRecord = BookRecord::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for BookRecord {
  type Error = String;
  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 4 {
      return Err(format!("book record does not have 4 items {:?}", v));
    }

    let rate: f64 = v[2].expect("book record rate")?;
    let amount: f64 = v[3].expect("book record amount")?;

    Ok(Self {rate, amount})
  }
}

/**
 * RecordUpdate enum conversion traits
 * use:
 *  let val = match serde_json::from_str(r#"["o",0,"0.12900000","1.03377186"]"#);
 *  let records:: RecordUpdate = RecordUpdate::try_from(&val)
 **/

impl<'a> TryFrom<&'a JsonValue> for RecordUpdate {
  type Error = String;

  fn try_from(v: &'a JsonValue) -> Result<Self, Self::Error> {
    let err = |msg| Err(format!("book update record {} {:?}", msg, v));
    if v.len() < 3 {
      return err("has less than 3 items");
    }

    match v[0].as_str() {
      Some("o") => {
        let direction: u64 = v[1].expect("book record direction")?;
        let record = BookRecord::try_from(v)?;
        match direction {
          0 => Ok(RecordUpdate::SellTotal(record)),
          1 => Ok(RecordUpdate::BuyTotal(record)),
          _ => err("has unknown dir")
        }
      },
      Some("t") => {
        let direction: u64 = v[2].expect("book record direction")?;
        let record = TradeRecord::try_from(v)?;
        match direction {
          0 => Ok(RecordUpdate::Sell(record)),
          1 => Ok(RecordUpdate::Buy(record)),
          _ => err("has unknown dir")
        }
      },
      _ => err("has unknown type")
    }
  }
}

/**
 * BookUpdate conversion traits
 * use:
 *  let update:: BookUpdate = BookUpdate::from_str(
 *    r#"[189,4811375,[["o",1,"0.12774723","0.00000000"],["t","714109",1,"0.12900000","1.03377186",1504163835]]]"#
 *  )
 **/

impl FromStr for BookUpdate {
  type Err = String;
  fn from_str(order: &str) -> Result<Self, Self::Err> {
    let v = json::parse(order).map_err(|err| err.to_string())?;
    Ok(BookUpdate::try_from(v)?)
  }
}

impl TryFrom<JsonValue> for BookUpdate {
  type Error = String;
  fn try_from(v: JsonValue) -> Result<Self, Self::Error> {
    if v.len() != 3 {
      return Err(format!("book update is not triple {:?}", v));
    }
    if !v[2].is_array() {
      return Err(format!("book update records: expected array got {:?}", v));
    }

    let book_id: u64 = v[0].expect("book update book_id")?;
    let record_id: u64 = v[1].expect("book update record_id")?;
    let mut records: Vec<RecordUpdate> = vec![];
    for record in v[2].members() {
      records.push(RecordUpdate::try_from(record)?)
    };

    Ok(Self { book_id, record_id, records })
  }
}

#[cfg(test)]
mod tests {
  use super::BookUpdate;
  use std::str::FromStr;
  use test::Bencher;
  use json;

  #[test]
  fn json_deserialize_order_update() {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Err(error) => panic!("failed to process json {}", error),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err1() {
    let order = r#"[189,4811424,[["o",1,"bad","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err2() {
    let order = r#"[189,4811424]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err3() {
    let order = r#"[189,4811424,[["f",1,"0.120000","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[test]
  fn json_deserialize_order_update_err4() {
    let order = r#"[189,4811424,[["o",3,"0.120000","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    match BookUpdate::from_str(order) {
      Ok(val) => panic!("processed wrong json {:?}", val),
      _ => ()
    }
  }

  #[bench]
  fn json_read_order_updates(b: &mut Bencher) {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    b.iter(|| BookUpdate::from_str(&order));
  }

  #[bench]
  fn json_read_order_updates_json(b: &mut Bencher) {
    let order = r#"[189,4811424,[["o",1,"0.12906425","0.02691207"],["t","714116",0,"0.12906425","0.05946471",1504163848]]]"#;
    b.iter(|| json::parse(order));
  }
}<|endoftext|>


<commit_before>extern crate rs_poker;
use rs_poker::core::Hand;
use rs_poker::holdem::Game;

fn main() {
    let hands = ["Adkh", "8c8s"]
        .iter()
        .map(|s| Hand::new_from_str(s).expect("Should be able to create a hand."))
        .collect();
    let mut g = Game::new_with_hands(hands).expect("Should be able to create a game.");
    let mut wins: [u64; 2] = [0, 0];
    for _ in 0..200000000 {
        let r = g.simulate().expect("There should be one best rank.");
        g.reset();
        wins[r.0] += 1
    }
    println!("Wins = {:?}", wins);
}
<commit_msg>Fewer loops on the example to make debugging more stable.<commit_after>extern crate rs_poker;
use rs_poker::core::Hand;
use rs_poker::holdem::Game;

fn main() {
    let hands = ["Adkh", "8c8s"]
        .iter()
        .map(|s| Hand::new_from_str(s).expect("Should be able to create a hand."))
        .collect();
    let mut g = Game::new_with_hands(hands).expect("Should be able to create a game.");
    let mut wins: [u64; 2] = [0, 0];
    for _ in 0..2000000 {
        let r = g.simulate().expect("There should be one best rank.");
        g.reset();
        wins[r.0] += 1
    }
    println!("Wins = {:?}", wins);
}
<|endoftext|>


<commit_before>use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::linux_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
    base.stack_probes = true;
    base.has_elf_tls = false;
    // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
    // breaks code gen. See LLVM bug 36743
    base.needs_plt = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "linux".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: base,
    })
}
<commit_msg>Disable stack probing for gnux32.<commit_after>use crate::spec::{LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::linux_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
    // BUG: temporarily workaround #59674
    base.stack_probes = false;
    base.has_elf_tls = false;
    // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
    // breaks code gen. See LLVM bug 36743
    base.needs_plt = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "linux".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: base,
    })
}
<|endoftext|>


<commit_before>use analysis::bounds::Bound;
use analysis::imports::Imports;
use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::signals;
use analysis::signatures::{Signature, Signatures};
use analysis::trampolines;
use config::{self, GObject, PropertyGenerateFlags};
use env::Env;
use library;
use nameutil;
use traits::*;
use version::Version;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
    pub bound: Option<Bound>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            trampolines,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if getter.is_none() && setter.is_none() {
            continue;
        }

        let type_string = rust_type(env, prop.typ);
        if let Some(prop) = getter {
            if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
                imports.add("glib::StaticType", prop.version);
            }

            properties.push(prop);
        }
        if let Some(prop) = setter {
            if let Ok(ref s) = used_rust_type(env, prop.typ, true) {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
            }

            if let Some(ref bound, ..) = prop.bound {
                if bound.bound_type.need_isa() {
                    imports.add("glib::object::IsA", prop.version);
                    imports.add("glib", prop.version);
                }
            }

            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let type_name = type_tid.full_name(&env.library);
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next();
    let generate_set = generate.is_some();
    let generate = generate.unwrap_or_else(PropertyGenerateFlags::all);

    let name_for_func = nameutil::signal_to_snake(&name);
    let var_name = nameutil::mangle_keywords(&*name_for_func).into_owned();
    let get_func_name = format!("get_property_{}", name_for_func);
    let set_func_name = format!("set_property_{}", name_for_func);
    let check_get_func_name = format!("get_{}", name_for_func);
    let check_set_func_name = format!("set_{}", name_for_func);

    let mut readable = prop.readable;
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable
    };
    let mut notifable = !prop.construct_only;
    if generate_set && generate.contains(PropertyGenerateFlags::GET) && !readable {
        warn!(
            "Attempt to generate getter for notreadable property \"{}.{}\"",
            type_name, name
        );
    }
    if generate_set && generate.contains(PropertyGenerateFlags::SET) && !writable {
        warn!(
            "Attempt to generate setter for nonwritable property \"{}.{}\"",
            type_name, name
        );
    }
    readable &= generate.contains(PropertyGenerateFlags::GET);
    writable &= generate.contains(PropertyGenerateFlags::SET);
    if generate_set {
        notifable = generate.contains(PropertyGenerateFlags::NOTIFY);
    }

    if readable {
        let (has, version) = Signature::has_for_property(env, &check_get_func_name,
                                                         true, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            readable = false;
        }
    }
    if writable {
        let (has, version) = Signature::has_for_property(env, &check_set_func_name,
                                                         false, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            writable = false;
        }
    }

    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    let getter = if readable {
        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound: None,
        })
    } else {
        None
    };

    let setter = if writable {
        let bound = Bound::get_for_property_setter(env, &var_name, prop.typ, nullable);
        Some(Property {
            name: name.clone(),
            var_name,
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound,
        })
    } else {
        None
    };

    if !generate_trait && (writable || readable || notifable) {
        imports.add("glib::object::ObjectType", prop_version);
    }

    let notify_signal = if notifable {
        let mut used_types: Vec<String> = Vec::with_capacity(4);
        let trampoline_name = trampolines::analyze(
            env,
            &library::Signal {
                name: format!("notify::{}", name),
                parameters: Vec::new(),
                ret: library::Parameter {
                    name: "".into(),
                    typ: env
                        .library
                        .find_type(library::INTERNAL_NAMESPACE, "none")
                        .unwrap(),
                    c_type: "none".into(),
                    instance_parameter: false,
                    direction: library::ParameterDirection::Return,
                    transfer: library::Transfer::None,
                    caller_allocates: false,
                    nullable: library::Nullable(false),
                    allow_none: false,
                    array_length: None,
                    is_error: false,
                    doc: None,
                    scope: library::ParameterScope::None,
                    closure: None,
                    destroy: None,
                },
                is_action: false,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc: None,
                doc_deprecated: None,
            },
            type_tid,
            generate_trait,
            &[],
            trampolines,
            obj,
            &mut used_types,
            prop_version,
        );

        if trampoline_name.is_ok() {
            imports.add_used_types(&used_types, prop_version);
            if generate_trait {
                imports.add("glib::object::Cast", prop_version);
            }
            imports.add("glib::signal::connect_raw", prop_version);
            imports.add("glib::signal::SignalHandlerId", prop_version);
            imports.add("std::mem::transmute", prop_version);
            imports.add("std::boxed::Box as Box_", prop_version);
            imports.add("glib_ffi", prop_version);

            Some(signals::Info {
                connect_name: format!("connect_property_{}_notify", name_for_func),
                signal_name: format!("notify::{}", name),
                trampoline_name,
                action_emit_name: None,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc_hidden: false,
            })
        } else {
            None
        }
    } else {
        None
    };

    (getter, setter, notify_signal)
}
<commit_msg>notifable -> notifiable<commit_after>use analysis::bounds::Bound;
use analysis::imports::Imports;
use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::signals;
use analysis::signatures::{Signature, Signatures};
use analysis::trampolines;
use config::{self, GObject, PropertyGenerateFlags};
use env::Env;
use library;
use nameutil;
use traits::*;
use version::Version;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
    pub bound: Option<Bound>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            trampolines,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if getter.is_none() && setter.is_none() {
            continue;
        }

        let type_string = rust_type(env, prop.typ);
        if let Some(prop) = getter {
            if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
                imports.add("glib::StaticType", prop.version);
            }

            properties.push(prop);
        }
        if let Some(prop) = setter {
            if let Ok(ref s) = used_rust_type(env, prop.typ, true) {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
            }

            if let Some(ref bound, ..) = prop.bound {
                if bound.bound_type.need_isa() {
                    imports.add("glib::object::IsA", prop.version);
                    imports.add("glib", prop.version);
                }
            }

            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let type_name = type_tid.full_name(&env.library);
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next();
    let generate_set = generate.is_some();
    let generate = generate.unwrap_or_else(PropertyGenerateFlags::all);

    let name_for_func = nameutil::signal_to_snake(&name);
    let var_name = nameutil::mangle_keywords(&*name_for_func).into_owned();
    let get_func_name = format!("get_property_{}", name_for_func);
    let set_func_name = format!("set_property_{}", name_for_func);
    let check_get_func_name = format!("get_{}", name_for_func);
    let check_set_func_name = format!("set_{}", name_for_func);

    let mut readable = prop.readable;
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable
    };
    let mut notifiable = !prop.construct_only;
    if generate_set && generate.contains(PropertyGenerateFlags::GET) && !readable {
        warn!(
            "Attempt to generate getter for notreadable property \"{}.{}\"",
            type_name, name
        );
    }
    if generate_set && generate.contains(PropertyGenerateFlags::SET) && !writable {
        warn!(
            "Attempt to generate setter for nonwritable property \"{}.{}\"",
            type_name, name
        );
    }
    readable &= generate.contains(PropertyGenerateFlags::GET);
    writable &= generate.contains(PropertyGenerateFlags::SET);
    if generate_set {
        notifiable = generate.contains(PropertyGenerateFlags::NOTIFY);
    }

    if readable {
        let (has, version) = Signature::has_for_property(env, &check_get_func_name,
                                                         true, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            readable = false;
        }
    }
    if writable {
        let (has, version) = Signature::has_for_property(env, &check_set_func_name,
                                                         false, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            writable = false;
        }
    }

    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    let getter = if readable {
        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound: None,
        })
    } else {
        None
    };

    let setter = if writable {
        let bound = Bound::get_for_property_setter(env, &var_name, prop.typ, nullable);
        Some(Property {
            name: name.clone(),
            var_name,
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound,
        })
    } else {
        None
    };

    if !generate_trait && (writable || readable || notifiable) {
        imports.add("glib::object::ObjectType", prop_version);
    }

    let notify_signal = if notifiable {
        let mut used_types: Vec<String> = Vec::with_capacity(4);
        let trampoline_name = trampolines::analyze(
            env,
            &library::Signal {
                name: format!("notify::{}", name),
                parameters: Vec::new(),
                ret: library::Parameter {
                    name: "".into(),
                    typ: env
                        .library
                        .find_type(library::INTERNAL_NAMESPACE, "none")
                        .unwrap(),
                    c_type: "none".into(),
                    instance_parameter: false,
                    direction: library::ParameterDirection::Return,
                    transfer: library::Transfer::None,
                    caller_allocates: false,
                    nullable: library::Nullable(false),
                    allow_none: false,
                    array_length: None,
                    is_error: false,
                    doc: None,
                    scope: library::ParameterScope::None,
                    closure: None,
                    destroy: None,
                },
                is_action: false,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc: None,
                doc_deprecated: None,
            },
            type_tid,
            generate_trait,
            &[],
            trampolines,
            obj,
            &mut used_types,
            prop_version,
        );

        if trampoline_name.is_ok() {
            imports.add_used_types(&used_types, prop_version);
            if generate_trait {
                imports.add("glib::object::Cast", prop_version);
            }
            imports.add("glib::signal::connect_raw", prop_version);
            imports.add("glib::signal::SignalHandlerId", prop_version);
            imports.add("std::mem::transmute", prop_version);
            imports.add("std::boxed::Box as Box_", prop_version);
            imports.add("glib_ffi", prop_version);

            Some(signals::Info {
                connect_name: format!("connect_property_{}_notify", name_for_func),
                signal_name: format!("notify::{}", name),
                trampoline_name,
                action_emit_name: None,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc_hidden: false,
            })
        } else {
            None
        }
    } else {
        None
    };

    (getter, setter, notify_signal)
}
<|endoftext|>


<commit_before>//! This module makes it possible to map `chrono::DateTime` values to postgres `Date`
//! and `Timestamp` fields. It is enabled with the `chrono` feature.
extern crate chrono;
extern crate byteorder;

use std::error::Error;
use std::io::Write;
use self::byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use self::chrono::{Duration, NaiveDateTime, NaiveDate};

use expression::AsExpression;
use expression::bound::Bound;
use query_source::Queriable;
use types::impls::option::UnexpectedNullError;
use types::{self, FromSql, IsNull, Timestamp, ToSql};

expression_impls! {
    Timestamp -> NaiveDateTime,
}

queriable_impls! {
    Timestamp -> NaiveDateTime,
}

// Postgres timestamps start from January 1st 2000.
fn pg_epoch() -> NaiveDateTime {
    NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0)
}

impl FromSql<Timestamp> for NaiveDateTime {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error>> {
        let mut bytes = not_none!(bytes);
        let offset: i64 = try!(bytes.read_i64::<BigEndian>());
        Ok(pg_epoch() + Duration::microseconds(offset))
    }
}

impl ToSql<Timestamp> for NaiveDateTime {
    fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error>> {
        let time = match (*self - pg_epoch()).num_microseconds() {
            Some(time) => time,
            None => {
                let error_message = format!("{:?} as microseconds is too large to fit in an i64", self);
                return Err(Box::<Error + Send + Sync>::from(error_message));
            }
        };
        try!(out.write_i64::<BigEndian>(time));
        Ok(IsNull::No)
    }
}
<commit_msg>Refactor the implementation of `chrono` to be about mapping not bytes<commit_after>//! This module makes it possible to map `chrono::DateTime` values to postgres `Date`
//! and `Timestamp` fields. It is enabled with the `chrono` feature.
extern crate chrono;

use std::error::Error;
use std::io::Write;
use self::chrono::{Duration, NaiveDateTime, NaiveDate};

use expression::AsExpression;
use expression::bound::Bound;
use query_source::Queriable;
use super::PgTimestamp;
use types::{self, FromSql, IsNull, Timestamp, ToSql};

expression_impls! {
    Timestamp -> NaiveDateTime,
}

queriable_impls! {
    Timestamp -> NaiveDateTime,
}

// Postgres timestamps start from January 1st 2000.
fn pg_epoch() -> NaiveDateTime {
    NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0)
}

impl FromSql<Timestamp> for NaiveDateTime {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error>> {
        let PgTimestamp(offset) = try!(FromSql::<Timestamp>::from_sql(bytes));
        Ok(pg_epoch() + Duration::microseconds(offset))
    }
}

impl ToSql<Timestamp> for NaiveDateTime {
    fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error>> {
        let time = match (*self - pg_epoch()).num_microseconds() {
            Some(time) => time,
            None => {
                let error_message = format!("{:?} as microseconds is too large to fit in an i64", self);
                return Err(Box::<Error + Send + Sync>::from(error_message));
            }
        };
        ToSql::<Timestamp>::to_sql(&PgTimestamp(time), out)
    }
}
<|endoftext|>


<commit_before>use super::function::Function;
use super::identifier::Identifier;
use std::collections::VecMap;
use std::borrow::Cow;

pub type CowScope<'a> = Cow<'a, Scope<'a>, Scope<'a>>;

/// Holds a number of variables, functions and their values.
#[derive(Clone)]
pub struct Scope<'a> {
	vars: VecMap<f32>,
	funcs: VecMap<&'a (Function + 'static)>,
}

impl<'a> Scope<'a> {
	/// Constructs an empty scope object.
	pub fn new() -> Scope<'a> {
		Scope {
			vars: VecMap::new(),
			funcs: VecMap::new(),
		}
	}

	pub fn set_var(&mut self, id: Identifier, value: f32) {
		self.vars.insert(id, value);
	}

	pub fn get_var(&self, id: Identifier) -> Option<f32> {
		self.vars.get(&id).map(|x| *x)
	}

	pub fn set_func(&mut self, id: Identifier, func: &'a (Function + 'static)) {
		self.funcs.insert(id, func);
	}

	pub fn get_func(&self, id: Identifier) -> Option<&'a (Function + 'static)> {
		self.funcs.get(&id).map(|x| *x)
	}
}
<commit_msg>Give scope more of a type system<commit_after>use super::function::Function;
use super::identifier::Identifier;
use std::collections::VecMap;
use std::borrow::Cow;

#[derive(Clone)]
enum Value<'a> {
	Number(f32),
	Function(&'a (Function + 'static)),
}

pub type CowScope<'a> = Cow<'a, Scope<'a>, Scope<'a>>;

/// Holds a number of variables, functions and their values.
#[derive(Clone)]
pub struct Scope<'a> {
	values: VecMap<Value<'a>>,
}

// TODO warn on type errors
impl<'a> Scope<'a> {
	/// Constructs an empty scope object.
	pub fn new() -> Scope<'a> {
		Scope {
			values: VecMap::new(),
		}
	}

	pub fn set_var(&mut self, id: Identifier, value: f32) {
		self.values.insert(id, Value::Number(value));
	}

	pub fn get_var(&self, id: Identifier) -> Option<f32> {
		match self.values.get(&id) {
			Some(&Value::Number(x)) => Some(x),
			_ => None,
		}
	}

	pub fn set_func(&mut self, id: Identifier, func: &'a (Function + 'static)) {
		self.values.insert(id, Value::Function(func));
	}

	pub fn get_func(&self, id: Identifier) -> Option<&'a (Function + 'static)> {
		match self.values.get(&id) {
			Some(&Value::Function(x)) => Some(x),
			_ => None,
		}
	}
}
<|endoftext|>