<commit_before>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: None,
                text: "Normal mode".to_string(),
                msg: Msg::SetMode(Mode::Normal),
            },
            Action {
                image: None,
                text: "Edit mode".to_string(),
                msg: Msg::SetMode(Mode::Edit),
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        self.field(&self.cursor)
    }

    pub fn field(&self, path: &Path) -> Option<Field> {
        let parent_path = parent(&self.cursor);

        match path.last() {
            Some(selector) => {
                let parent = self.file.lookup(&parent_path).unwrap();
                SCHEMA
                    .get_kind(&parent.kind)
                    .unwrap()
                    .get_field(&selector.field)
            }
            None => None,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(Some(file.root.clone()), &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        // let serialized = serde_json::to_string_pretty(file).expect("could not serialize to
        // JSON");
        let serialized = format!("root: {:?}\nfile: {:#?}", file.root, file);
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, path: &[Selector]) -> Vec<Path> {
        // log::info!("flatten: {:?}", path);
        match &self.file.lookup(path) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, child) in children.iter().enumerate() {
                        let new_path = append(
                            path,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_path.clone());
                        // log::info!("child: {:?}[{:?}]->{:?}", path, field.name, child);
                        paths.extend(self.flatten_paths(&new_path));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                path,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, hash: Option<Hash>, path: &[Selector]) -> Html {
        self.view_node_with_placeholder(hash, path, "◆")
    }

    fn view_node_with_placeholder(
        &self,
        hash: Option<Hash>,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if path == &self.hover {
            classes.push("hover".to_string());
        }

        let path_clone = path.to_vec();
        let onclick = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Select(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let onmouseover = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Hover(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let oninput = self.link.callback(move |e: InputData| {
            crate::types::Msg::SetNodeCommand(path_clone.clone(), e.value.clone())
        });

        let node_state = self.node_state.get(&path.to_vec());

        // let value = match self.file.lookup(path) {
        //     Some(node) => self.view_value(&node, &path),
        //     None => {
        //         html! {
        //             { format!("invalid: {:?}", path) }
        //         }
        //     }
        // };

        let value = match hash {
            Some(hash) => match self.file.lookup(path) {
                Some(node) => self.view_value(&node, &path),
                None => {
                    html! {
                        { format!("invalid: {:?}", hash) }
                    }
                }
            },
            None => {
                let selected_command_index = node_state
                    .as_ref()
                    .map(|s| s.selected_command_index)
                    .unwrap_or(0);
                let suggestions: Vec<_> = if selected {
                    node_state
                    .map(|v| v.parsed_commands.clone())
                    .unwrap_or_default()
                    .iter()
                    .enumerate()
                    .map(|(i, v)| {
                        let path_clone = path.to_vec();
                        let value_string = v.value.clone().unwrap_or_default();
                        let node = v.to_node();
                        let onclick = self.link.callback(move |e: MouseEvent| match node.clone() {
                            Some(node) => Msg::ReplaceNode(path_clone.clone(), node.clone(),true),
                            None => Msg::Noop,
                        });
                        let mut classes_item = vec!["block", "border"];
                        if i == selected_command_index {
                            classes_item.push("selected");
                        }
                        html! {
                            {value_string}
                        }
                    })
                    .collect()
                } else {
                    vec![]
                };
                let classes_dropdown = vec!["absolute", "z-10", "bg-white"];
                let id = command_input_id(&path);
                let command = node_state
                    .map(|s| s.raw_command.clone())
                    .unwrap_or_default();
                let style = format!("width: {}ch;", std::cmp::max(command.len(), 1));
                html! {

{ placeholder }

                            // {""}
                            <input id=id class="inline-block w-full" type="text" oninput=oninput value=command style=style />

                                { for suggestions }

                }
            }
        };
        // Use onmousedown to avoid re-selecting the node.
        html! {

                { value }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &Path) -> Html {
        self.view_child_with_placeholder(node, field_name, path, field_name)
    }

    pub fn view_child_with_placeholder(
        &self,
        node: &Node,
        field_name: &str,
        path: &Path,
        placeholder: &str,
    ) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        let hash = node
            .children
            .get(field_name)
            .and_then(|v| v.get(0))
            .cloned();
        // Empty list vs hole vs special value?
        // TODO: How to traverse nested lists in preorder?
        self.view_node_with_placeholder(hash, &path, placeholder)
    }

    /// Returns the head and children, separately.
    pub fn view_children(&self, node: &Node, field_name: &str, path: &Path) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = node.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let mut classes = vec!["node".to_string(), "placeholder".to_string()];
            if path == self.cursor {
                classes.push("selected".to_string());
            }
            if path == self.hover {
                classes.push("hover".to_string());
            }

            let path_clone = path.clone();
            let onclick = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Select(path_clone.clone())
            });

            let path_clone = path.clone();
            let onmouseover = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Hover(path_clone.clone())
            });

            // html! {
            //
{ field_name
            // }{ "▷" }
 }
            html! {

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, h)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(Some(h.clone()), &path)
            })
            .chain(std::iter::once({
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: children.len(),
                    },
                );
                self.view_node_with_placeholder(None, &path, &format!("{}▷", field_name))
            }))
            .collect::<Vec<_>>();
        (head, nodes)
    }

    fn view_value(&self, node: &Node, path: &[Selector]) -> Html {
        match SCHEMA.get_kind(&node.kind) {
            Some(kind) => kind.render(self, node, path),
            None => html! { { "unknown kind: " }{ node.kind.clone() } },
        }
    }
}

pub fn command_input_id(path: &[Selector]) -> String {
    let mut id = String::new();
    for selector in path {
        id.push_str(&selector.field);
        id.push_str(&selector.index.to_string());
    }
    id
}
<commit_msg>Vertical alignment<commit_after>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: None,
                text: "Normal mode".to_string(),
                msg: Msg::SetMode(Mode::Normal),
            },
            Action {
                image: None,
                text: "Edit mode".to_string(),
                msg: Msg::SetMode(Mode::Edit),
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        self.field(&self.cursor)
    }

    pub fn field(&self, path: &Path) -> Option<Field> {
        let parent_path = parent(&self.cursor);

        match path.last() {
            Some(selector) => {
                let parent = self.file.lookup(&parent_path).unwrap();
                SCHEMA
                    .get_kind(&parent.kind)
                    .unwrap()
                    .get_field(&selector.field)
            }
            None => None,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(Some(file.root.clone()), &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        // let serialized = serde_json::to_string_pretty(file).expect("could not serialize to
        // JSON");
        let serialized = format!("root: {:?}\nfile: {:#?}", file.root, file);
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, path: &[Selector]) -> Vec<Path> {
        // log::info!("flatten: {:?}", path);
        match &self.file.lookup(path) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, child) in children.iter().enumerate() {
                        let new_path = append(
                            path,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_path.clone());
                        // log::info!("child: {:?}[{:?}]->{:?}", path, field.name, child);
                        paths.extend(self.flatten_paths(&new_path));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                path,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, hash: Option<Hash>, path: &[Selector]) -> Html {
        self.view_node_with_placeholder(hash, path, "◆")
    }

    fn view_node_with_placeholder(
        &self,
        hash: Option<Hash>,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string(), "align-top".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if path == &self.hover {
            classes.push("hover".to_string());
        }

        let path_clone = path.to_vec();
        let onclick = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Select(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let onmouseover = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Hover(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let oninput = self.link.callback(move |e: InputData| {
            crate::types::Msg::SetNodeCommand(path_clone.clone(), e.value.clone())
        });

        let node_state = self.node_state.get(&path.to_vec());

        // let value = match self.file.lookup(path) {
        //     Some(node) => self.view_value(&node, &path),
        //     None => {
        //         html! {
        //             { format!("invalid: {:?}", path) }
        //         }
        //     }
        // };

        let value = match hash {
            Some(hash) => match self.file.lookup(path) {
                Some(node) => self.view_value(&node, &path),
                None => {
                    html! {
                        { format!("invalid: {:?}", hash) }
                    }
                }
            },
            None => {
                let selected_command_index = node_state
                    .as_ref()
                    .map(|s| s.selected_command_index)
                    .unwrap_or(0);
                let suggestions: Vec<_> = if selected {
                    node_state
                    .map(|v| v.parsed_commands.clone())
                    .unwrap_or_default()
                    .iter()
                    .enumerate()
                    .map(|(i, v)| {
                        let path_clone = path.to_vec();
                        let value_string = v.value.clone().unwrap_or_default();
                        let node = v.to_node();
                        let onclick = self.link.callback(move |e: MouseEvent| match node.clone() {
                            Some(node) => Msg::ReplaceNode(path_clone.clone(), node.clone(),true),
                            None => Msg::Noop,
                        });
                        let mut classes_item = vec!["block", "border"];
                        if i == selected_command_index {
                            classes_item.push("selected");
                        }
                        html! {
                            {value_string}
                        }
                    })
                    .collect()
                } else {
                    vec![]
                };
                let classes_dropdown = vec!["absolute", "z-10", "bg-white"];
                let id = command_input_id(&path);
                let command = node_state
                    .map(|s| s.raw_command.clone())
                    .unwrap_or_default();
                let style = format!("width: {}ch;", std::cmp::max(command.len(), 1));
                html! {

{ placeholder }

                            // {""}
                            <input id=id class="inline-block w-full" type="text" oninput=oninput value=command style=style />

                                { for suggestions }

                }
            }
        };
        // Use onmousedown to avoid re-selecting the node?
        html! {

                { value }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &Path) -> Html {
        self.view_child_with_placeholder(node, field_name, path, field_name)
    }

    pub fn view_child_with_placeholder(
        &self,
        node: &Node,
        field_name: &str,
        path: &Path,
        placeholder: &str,
    ) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        let hash = node
            .children
            .get(field_name)
            .and_then(|v| v.get(0))
            .cloned();
        // Empty list vs hole vs special value?
        // TODO: How to traverse nested lists in preorder?
        self.view_node_with_placeholder(hash, &path, placeholder)
    }

    /// Returns the head and children, separately.
    pub fn view_children(&self, node: &Node, field_name: &str, path: &Path) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = node.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let mut classes = vec!["node".to_string(), "placeholder".to_string()];
            if path == self.cursor {
                classes.push("selected".to_string());
            }
            if path == self.hover {
                classes.push("hover".to_string());
            }

            let path_clone = path.clone();
            let onclick = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Select(path_clone.clone())
            });

            let path_clone = path.clone();
            let onmouseover = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Hover(path_clone.clone())
            });

            // html! {
            //
{ field_name
            // }{ "▷" }
 }
            html! {

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, h)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(Some(h.clone()), &path)
            })
            .chain(std::iter::once({
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: children.len(),
                    },
                );
                self.view_node_with_placeholder(None, &path, &format!("{}▷", field_name))
            }))
            .collect::<Vec<_>>();
        (head, nodes)
    }

    fn view_value(&self, node: &Node, path: &[Selector]) -> Html {
        match SCHEMA.get_kind(&node.kind) {
            Some(kind) => kind.render(self, node, path),
            None => html! { { "unknown kind: " }{ node.kind.clone() } },
        }
    }
}

pub fn command_input_id(path: &[Selector]) -> String {
    let mut id = String::new();
    for selector in path {
        id.push_str(&selector.field);
        id.push_str(&selector.index.to_string());
    }
    id
}
<|endoftext|>


<commit_before>use clap::{Parser, Subcommand, Args};

#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
struct Cli {
    #[clap(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Adds files to myapp
    Add(Add),
}

#[derive(Args)]
struct Add {
    name: Option<String>
}

fn main() {
    let cli = Cli::parse();

    // You can check for the existence of subcommands, and if found use their
    // matches just as you would the top level cmd
    match &cli.command {
        Commands::Add { name } => {
            println!("'myapp add' was used, name is: {:?}", name)
        }
    }
}
<commit_msg>style: Clean up<commit_after>use clap::{Args, Parser, Subcommand};

#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
struct Cli {
    #[clap(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Adds files to myapp
    Add(Add),
}

#[derive(Args)]
struct Add {
    name: Option<String>,
}

fn main() {
    let cli = Cli::parse();

    // You can check for the existence of subcommands, and if found use their
    // matches just as you would the top level cmd
    match &cli.command {
        Commands::Add(name) => {
            println!("'myapp add' was used, name is: {:?}", name.name)
        }
    }
}
<|endoftext|>


<commit_before>use std::rand::{Rng, TaskRng, task_rng};
use std::vec;

/// Gen wraps a `rand::Rng` with parameters to control the distribution of
/// random values.
pub trait Gen : Rng {
    fn size(&self) -> uint;
}

/// StdGen is the default implementation of `Gen`.
pub struct StdGen<R> {
    rng: R,
    size: uint,
}

impl<R: Rng> Rng for StdGen<R> {
    fn next_u32(&mut self) -> u32 { self.rng.next_u32() }
}

impl<R: Rng> Gen for StdGen<R> {
    fn size(&self) -> uint { self.size }
}

/// Arbitrary specifies how values of a particular type should be randomly
/// generated.
///
/// It is different from the `std::Rand` trait in that it uses a `Gen` to
/// control the distribution of random values.
pub trait Arbitrary {
    fn arbitrary<G: Gen>(g: &mut G) -> Self;
}

impl<A: Arbitrary> Arbitrary for ~[A] {
    fn arbitrary<G: Gen>(g: &mut G) -> ~[A] {
        let size = { let s = g.size(); g.gen_range(0, s) };
        vec::from_fn(size, |_| Arbitrary::arbitrary(g))
    }
}

impl<A: Arbitrary> Arbitrary for Option<A> {
    fn arbitrary<G: Gen>(g: &mut G) -> Option<A> {
        if g.gen() {
            None
        } else {
            Some(Arbitrary::arbitrary(g))
        }
    }
}

impl<A: Arbitrary, B: Arbitrary> Arbitrary for Result<A, B> {
    fn arbitrary<G: Gen>(g: &mut G) -> Result<A, B> {
        if g.gen() {
            Ok(Arbitrary::arbitrary(g))
        } else {
            Err(Arbitrary::arbitrary(g))
        }
    }
}

impl<A: Arbitrary, B: Arbitrary> Arbitrary for (A, B) {
    fn arbitrary<G: Gen>(g: &mut G) -> (A, B) {
        return (Arbitrary::arbitrary(g), Arbitrary::arbitrary(g))
    }
}

impl<A: Arbitrary, B: Arbitrary, C: Arbitrary> Arbitrary for (A, B, C) {
    fn arbitrary<G: Gen>(g: &mut G) -> (A, B, C) {
        return (
            Arbitrary::arbitrary(g),
            Arbitrary::arbitrary(g),
            Arbitrary::arbitrary(g),
        )
    }
}

impl Arbitrary for () {
    fn arbitrary<G: Gen>(_: &mut G) -> () { () }
}

impl Arbitrary for bool {
    fn arbitrary<G: Gen>(g: &mut G) -> bool { g.gen() }
}

impl Arbitrary for ~str {
    fn arbitrary<G: Gen>(g: &mut G) -> ~str {
        let size = { let s = g.size(); g.gen_range(0, s) };
        g.gen_ascii_str(size)
    }
}

impl Arbitrary for char {
    fn arbitrary<G: Gen>(g: &mut G) -> char { g.gen() }
}

impl Arbitrary for int {
    fn arbitrary<G: Gen>(g: &mut G) -> int {
        let s = g.size(); g.gen_range(-(s as int), s as int)
    }
}

impl Arbitrary for i8 {
    fn arbitrary<G: Gen>(g: &mut G) -> i8 {
        let s = g.size(); g.gen_range(-(s as i8), s as i8)
    }
}

impl Arbitrary for i16 {
    fn arbitrary<G: Gen>(g: &mut G) -> i16 {
        let s = g.size(); g.gen_range(-(s as i16), s as i16)
    }
}

impl Arbitrary for i32 {
    fn arbitrary<G: Gen>(g: &mut G) -> i32 {
        let s = g.size(); g.gen_range(-(s as i32), s as i32)
    }
}

impl Arbitrary for i64 {
    fn arbitrary<G: Gen>(g: &mut G) -> i64 {
        let s = g.size(); g.gen_range(-(s as i64), s as i64)
    }
}

impl Arbitrary for uint {
    fn arbitrary<G: Gen>(g: &mut G) -> uint {
        let s = g.size(); g.gen_range(0, s)
    }
}

impl Arbitrary for u8 {
    fn arbitrary<G: Gen>(g: &mut G) -> u8 {
        let s = g.size(); g.gen_range(0, s as u8)
    }
}

impl Arbitrary for u16 {
    fn arbitrary<G: Gen>(g: &mut G) -> u16 {
        let s = g.size(); g.gen_range(0, s as u16)
    }
}

impl Arbitrary for u32 {
    fn arbitrary<G: Gen>(g: &mut G) -> u32 {
        let s = g.size(); g.gen_range(0, s as u32)
    }
}

impl Arbitrary for u64 {
    fn arbitrary<G: Gen>(g: &mut G) -> u64 {
        let s = g.size(); g.gen_range(0, s as u64)
    }
}

/// Returns a random value according to `A`'s `Arbitrary` implementation using
/// the default `Gen`.
pub fn arbitrary<A: Arbitrary>() -> A {
    Arbitrary::arbitrary(&mut default_gen())
}

/// Returns a default implementation for `Gen` using a task-local random number
/// generator.
pub fn default_gen() -> StdGen<TaskRng> {
    gen(task_rng(), 20)
}

/// Returns a `Gen` with the given configuration.
///
/// The `size` parameter controls the size of random values generated.
/// For example, it specifies the maximum length of a randomly generator vector
/// and also will specify the maximum magnitude of a randomly generated number.
pub fn gen<R: Rng>(rng: R, size: uint) -> StdGen<R> {
    StdGen{rng: rng, size: size}
}

#[cfg(test)]
mod test {
    use std::iter;
    use std::rand;

    #[test]
    fn unit() {
        assert_eq!(arby::<()>(), ());
    }

    #[test]
    fn int() {
        rep(|| { let n: int = arby(); assert!(n >= -5 && n <= 5); } );
    }

    #[test]
    fn uint() {
        rep(|| { let n: uint = arby(); assert!(n <= 5); } );
    }

    fn arby<A: super::Arbitrary>() -> A {
        super::Arbitrary::arbitrary(&mut gen())
    }

    fn gen() -> super::StdGen<rand::TaskRng> {
        super::gen(rand::task_rng(), 5)
    }

    fn rep(f: ||) {
        for _ in iter::range(0, 100) {
            f()
        }
    }
}
<commit_msg>hide StdGen fields<commit_after>use std::rand::{Rng, TaskRng, task_rng};
use std::vec;

/// Gen wraps a `rand::Rng` with parameters to control the distribution of
/// random values.
pub trait Gen : Rng {
    fn size(&self) -> uint;
}

/// StdGen is the default implementation of `Gen`.
pub struct StdGen<R> {
    priv rng: R,
    priv size: uint,
}

impl<R: Rng> Rng for StdGen<R> {
    fn next_u32(&mut self) -> u32 { self.rng.next_u32() }
}

impl<R: Rng> Gen for StdGen<R> {
    fn size(&self) -> uint { self.size }
}

/// Arbitrary specifies how values of a particular type should be randomly
/// generated.
///
/// It is different from the `std::Rand` trait in that it uses a `Gen` to
/// control the distribution of random values.
pub trait Arbitrary {
    fn arbitrary<G: Gen>(g: &mut G) -> Self;
}

impl<A: Arbitrary> Arbitrary for ~[A] {
    fn arbitrary<G: Gen>(g: &mut G) -> ~[A] {
        let size = { let s = g.size(); g.gen_range(0, s) };
        vec::from_fn(size, |_| Arbitrary::arbitrary(g))
    }
}

impl<A: Arbitrary> Arbitrary for Option<A> {
    fn arbitrary<G: Gen>(g: &mut G) -> Option<A> {
        if g.gen() {
            None
        } else {
            Some(Arbitrary::arbitrary(g))
        }
    }
}

impl<A: Arbitrary, B: Arbitrary> Arbitrary for Result<A, B> {
    fn arbitrary<G: Gen>(g: &mut G) -> Result<A, B> {
        if g.gen() {
            Ok(Arbitrary::arbitrary(g))
        } else {
            Err(Arbitrary::arbitrary(g))
        }
    }
}

impl<A: Arbitrary, B: Arbitrary> Arbitrary for (A, B) {
    fn arbitrary<G: Gen>(g: &mut G) -> (A, B) {
        return (Arbitrary::arbitrary(g), Arbitrary::arbitrary(g))
    }
}

impl<A: Arbitrary, B: Arbitrary, C: Arbitrary> Arbitrary for (A, B, C) {
    fn arbitrary<G: Gen>(g: &mut G) -> (A, B, C) {
        return (
            Arbitrary::arbitrary(g),
            Arbitrary::arbitrary(g),
            Arbitrary::arbitrary(g),
        )
    }
}

impl Arbitrary for () {
    fn arbitrary<G: Gen>(_: &mut G) -> () { () }
}

impl Arbitrary for bool {
    fn arbitrary<G: Gen>(g: &mut G) -> bool { g.gen() }
}

impl Arbitrary for ~str {
    fn arbitrary<G: Gen>(g: &mut G) -> ~str {
        let size = { let s = g.size(); g.gen_range(0, s) };
        g.gen_ascii_str(size)
    }
}

impl Arbitrary for char {
    fn arbitrary<G: Gen>(g: &mut G) -> char { g.gen() }
}

impl Arbitrary for int {
    fn arbitrary<G: Gen>(g: &mut G) -> int {
        let s = g.size(); g.gen_range(-(s as int), s as int)
    }
}

impl Arbitrary for i8 {
    fn arbitrary<G: Gen>(g: &mut G) -> i8 {
        let s = g.size(); g.gen_range(-(s as i8), s as i8)
    }
}

impl Arbitrary for i16 {
    fn arbitrary<G: Gen>(g: &mut G) -> i16 {
        let s = g.size(); g.gen_range(-(s as i16), s as i16)
    }
}

impl Arbitrary for i32 {
    fn arbitrary<G: Gen>(g: &mut G) -> i32 {
        let s = g.size(); g.gen_range(-(s as i32), s as i32)
    }
}

impl Arbitrary for i64 {
    fn arbitrary<G: Gen>(g: &mut G) -> i64 {
        let s = g.size(); g.gen_range(-(s as i64), s as i64)
    }
}

impl Arbitrary for uint {
    fn arbitrary<G: Gen>(g: &mut G) -> uint {
        let s = g.size(); g.gen_range(0, s)
    }
}

impl Arbitrary for u8 {
    fn arbitrary<G: Gen>(g: &mut G) -> u8 {
        let s = g.size(); g.gen_range(0, s as u8)
    }
}

impl Arbitrary for u16 {
    fn arbitrary<G: Gen>(g: &mut G) -> u16 {
        let s = g.size(); g.gen_range(0, s as u16)
    }
}

impl Arbitrary for u32 {
    fn arbitrary<G: Gen>(g: &mut G) -> u32 {
        let s = g.size(); g.gen_range(0, s as u32)
    }
}

impl Arbitrary for u64 {
    fn arbitrary<G: Gen>(g: &mut G) -> u64 {
        let s = g.size(); g.gen_range(0, s as u64)
    }
}

/// Returns a random value according to `A`'s `Arbitrary` implementation using
/// the default `Gen`.
pub fn arbitrary<A: Arbitrary>() -> A {
    Arbitrary::arbitrary(&mut default_gen())
}

/// Returns a default implementation for `Gen` using a task-local random number
/// generator.
pub fn default_gen() -> StdGen<TaskRng> {
    gen(task_rng(), 20)
}

/// Returns a `Gen` with the given configuration.
///
/// The `size` parameter controls the size of random values generated.
/// For example, it specifies the maximum length of a randomly generator vector
/// and also will specify the maximum magnitude of a randomly generated number.
pub fn gen<R: Rng>(rng: R, size: uint) -> StdGen<R> {
    StdGen{rng: rng, size: size}
}

#[cfg(test)]
mod test {
    use std::iter;
    use std::rand;

    #[test]
    fn unit() {
        assert_eq!(arby::<()>(), ());
    }

    #[test]
    fn int() {
        rep(|| { let n: int = arby(); assert!(n >= -5 && n <= 5); } );
    }

    #[test]
    fn uint() {
        rep(|| { let n: uint = arby(); assert!(n <= 5); } );
    }

    fn arby<A: super::Arbitrary>() -> A {
        super::Arbitrary::arbitrary(&mut gen())
    }

    fn gen() -> super::StdGen<rand::TaskRng> {
        super::gen(rand::task_rng(), 5)
    }

    fn rep(f: ||) {
        for _ in iter::range(0, 100) {
            f()
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Reorder the callback setup in rawtests<commit_after><|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests");
            println!("  clean          # remove the target directory");
            println!("  run            # build and execute src/main.rs");
            println!("");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
            let mut command = match os::self_exe_path() {
                Some(path) => {
                    let p1 = path.join("../lib/cargo").join(command.as_slice());
                    let p2 = path.join(command.as_slice());
                    println!("{} {}", p1.display(), p2.display());
                    if p1.exists() {
                        Command::new(p1)
                    } else if p2.exists() {
                        Command::new(p2)
                    } else {
                        Command::new(command)
                    }
                }
                None => Command::new(command),
            };
            let command = command
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_string());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<commit_msg>Remove accidental debugging print<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests");
            println!("  clean          # remove the target directory");
            println!("  run            # build and execute src/main.rs");
            println!("");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
            let mut command = match os::self_exe_path() {
                Some(path) => {
                    let p1 = path.join("../lib/cargo").join(command.as_slice());
                    let p2 = path.join(command.as_slice());
                    if p1.exists() {
                        Command::new(p1)
                    } else if p2.exists() {
                        Command::new(p2)
                    } else {
                        Command::new(command)
                    }
                }
                None => Command::new(command),
            };
            let command = command
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_string());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<|endoftext|>


<commit_before>#![crate_name="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]
#![feature(default_type_params)]
#![deny(warnings)]

extern crate collections;
extern crate debug;
extern crate regex;
extern crate semver;
extern crate serialize;
extern crate term;
extern crate time;
extern crate url;
#[phase(plugin)] extern crate regex_macros;
#[phase(plugin, link)] extern crate log;

extern crate docopt;
extern crate toml;
#[cfg(test)] extern crate hamcrest;

use std::os;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{stdout, stderr};
use std::io;
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use docopt::FlagParser;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

pub fn execute_main<'a,
                    T: FlagParser,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                        options_first: bool) {
    process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
}

pub fn call_main<'a,
        T: FlagParser,
        U: RepresentsJSON,
        V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<'a,
                                  T: FlagParser,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                                      options_first: bool) {
    process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
                                                       options_first));
}

pub fn call_main_without_stdin<'a,
                               T: FlagParser,
                               V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    exec(flags, shell)
}

fn process<'a, V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
    let mut shell = shell(true);
    let mut args = os::args();
    args.remove(0);
    process_executed(callback(args.as_slice(), &mut shell), &mut shell)
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell) {
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else if error.to_string().len() > 0 {
        let _ = shell.error(error.to_string());
    }

    if error.cause().is_some() || unknown {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        if unknown {
            let _ = shell.error(error.to_string());
        }
        error.detail().map(|detail| {
            let _ = shell.err().say(format!("{}", detail), BLACK);
        });
        error.cause().map(|err| {
            let _ = handle_cause(err, shell);
        });
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

pub fn version() -> String {
    format!("cargo {}", env!("CFG_VERSION"))
}

fn flags_from_args<T: FlagParser>(args: &[String],
                                  options_first: bool) -> CliResult<T> {
    let args = args.iter().map(|a| a.as_slice()).collect::<Vec<&str>>();
    let config = docopt::Config {
        options_first: options_first,
        help: true,
        version: Some(version()),
    };
    FlagParser::parse_args(config, args.as_slice()).map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::from_error(e, code)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<commit_msg>Lift the requirement that cargo is built with make<commit_after>#![crate_name="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]
#![feature(default_type_params)]
#![deny(warnings)]

extern crate collections;
extern crate debug;
extern crate regex;
extern crate semver;
extern crate serialize;
extern crate term;
extern crate time;
extern crate url;
#[phase(plugin)] extern crate regex_macros;
#[phase(plugin, link)] extern crate log;

extern crate docopt;
extern crate toml;
#[cfg(test)] extern crate hamcrest;

use std::os;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{stdout, stderr};
use std::io;
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use docopt::FlagParser;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

pub fn execute_main<'a,
                    T: FlagParser,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                        options_first: bool) {
    process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
}

pub fn call_main<'a,
        T: FlagParser,
        U: RepresentsJSON,
        V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<'a,
                                  T: FlagParser,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                                      options_first: bool) {
    process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
                                                       options_first));
}

pub fn call_main_without_stdin<'a,
                               T: FlagParser,
                               V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    exec(flags, shell)
}

fn process<'a, V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
    let mut shell = shell(true);
    let mut args = os::args();
    args.remove(0);
    process_executed(callback(args.as_slice(), &mut shell), &mut shell)
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell) {
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else if error.to_string().len() > 0 {
        let _ = shell.error(error.to_string());
    }

    if error.cause().is_some() || unknown {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        if unknown {
            let _ = shell.error(error.to_string());
        }
        error.detail().map(|detail| {
            let _ = shell.err().say(format!("{}", detail), BLACK);
        });
        error.cause().map(|err| {
            let _ = handle_cause(err, shell);
        });
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T: FlagParser>(args: &[String],
                                  options_first: bool) -> CliResult<T> {
    let args = args.iter().map(|a| a.as_slice()).collect::<Vec<&str>>();
    let config = docopt::Config {
        options_first: options_first,
        help: true,
        version: Some(version()),
    };
    FlagParser::parse_args(config, args.as_slice()).map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::from_error(e, code)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<|endoftext|>


<commit_before>//! The change log.

/// Release 0.7.0 (2021-01-31)
///
/// ## Breaking changes
///
/// ### Loading functions are now `unsafe`
///
/// A number of associated methods involved in loading a library were changed to
/// be `unsafe`. The affected functions are: [`Library::new`], [`os::unix::Library::new`],
/// [`os::unix::Library::open`], [`os::windows::Library::new`],
/// [`os::windows::Library::load_with_flags`]. This is the most prominent breaking change in this
/// release and affects majority of the users of `libloading`.
///
/// In order to see why it was necessary, consider the following snippet of C++ code:
///
/// ```c++
/// #include <vector>
/// #include <iostream>
///
/// static std::vector<unsigned int> UNSHUU = { 1, 2, 3 };
///
/// int main() {
///     std::cout << UNSHUU[0] << UNSHUU[1] << UNSHUU[2] << std::endl; // Prints 123
///     return 0;
/// }
/// ```
///
/// The `std::vector` type, much like in Rust's `Vec`, stores its contents in a buffer allocated on
/// the heap. In this example the vector object itself is stored and initialized as a static
/// variable – a compile time construct. The heap, on the other hand, is a runtime construct. And
/// yet the code works exactly as you'd expect – the vector contains numbers 1, 2 and 3 stored in
/// a buffer on heap. So, _what_ makes it work out, exactly?
///
/// Various executable and shared library formats define conventions and machinery to execute
/// arbitrary code when a program or a shared library is loaded. On systems using the PE format
/// (e.g. Windows) this is available via the optional `DllMain` initializer. Various systems
/// utilizing the ELF format take a sightly different approach of maintaining an array of function
/// pointers in the `.init_array` section. A very similar mechanism exists on systems that utilize
/// the Mach-O format.
///
/// For the C++ program above, the object stored in the `UNSHUU` global variable is constructed
/// by code run as part of such an initializer routine. This initializer is run before the entry
/// point (the `main` function) is executed, allowing for this magical behaviour to be possible.
/// Were the C++ code built as a shared library instead, the initialization routines would run as
/// the resulting shared library is loaded. In case of `libloading` – during the call to
/// `Library::new` and other methods affected by this change.
///
/// These initialization (and very closely related termination) routines can be utilized outside of
/// C++ too. Anybody can build a shared library in variety of different programming languages and
/// set up the initializers to execute arbitrary code. Potentially code that does all sorts of
/// wildly unsound stuff.
///
/// The routines are executed by components that are an integral part of the operating system.
/// Changing or controlling the operation of these components is infeasible. With that in
/// mind, the initializer and termination routines are something anybody loading a library must
/// carefully evaluate the libraries loaded for soundness.
///
/// In practice, a vast majority of the libraries can be considered a good citizen and their
/// initialization and termination routines, if they have any at all, can be trusted to be sound.
///
/// Also see: [issue #86].
///
/// ### Better & more consistent default behaviour on UNIX systems
///
/// On UNIX systems the [`Library::new`], [`os::unix::Library::new`] and
/// [`os::unix::Library::this`] methods have been changed to use
/// [RTLD_LAZY] | [RTLD_LOCAL] as the default set of loader options (previously:
/// [`RTLD_NOW`]). This has a couple benefits. Namely:
///
/// * Lazy binding is generally quicker to execute when only a subset of symbols from a library are
///   used and is typically the default when neither `RTLD_LAZY` nor `RTLD_NOW` are specified when
///   calling the underlying `dlopen` API;
/// * On most UNIX systems (macOS being a notable exception) `RTLD_LOCAL` is the default when
///   neither `RTLD_LOCAL` nor [`RTLD_GLOBAL`] are specified. The explicit setting of the
///   `RTLD_LOCAL` flag makes this behaviour consistent across platforms.
///
/// ### Dropped support for Windows XP/Vista
///
/// The (broken) support for Windows XP and Windows Vista environments was removed. This was
/// prompted primarily by a similar policy change in the [Rust
/// project](https://github.com/rust-lang/compiler-team/issues/378) but also as an acknowledgement
/// to the fact that `libloading` never worked in these environments anyway.
///
/// ### More accurate error variant names
///
/// Finally, the `Error::LoadLibraryW` renamed to [`Error::LoadLibraryExW`] to more accurately
/// represent the underlying API that's failing. No functional changes as part of this rename
/// intended.
///
/// [issue #86]: https://github.com/nagisa/rust_libloading/issues/86
/// [`Library::new`]: crate::Library::new
/// [`Error::LoadLibraryExW`]: crate::Error::LoadLibraryExW
/// [`os::unix::Library::this`]: crate::os::unix::Library::this
/// [`os::unix::Library::new`]: crate::os::unix::Library::new
/// [`os::unix::Library::open`]: crate::os::unix::Library::new
/// [`os::windows::Library::new`]: crate::os::windows::Library::new
/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
/// [`RTLD_NOW`]: crate::os::unix::RTLD_NOW
/// [RTLD_LAZY]: crate::os::unix::RTLD_LAZY
/// [RTLD_LOCAL]: crate::os::unix::RTLD_LOCAL
/// [`RTLD_GLOBAL`]: crate::os::unix::RTLD_GLOBAL
pub mod r0_7_0 {}

/// Release 0.6.7 (2021-01-14)
///
/// * Added a [`os::windows::Library::open_already_loaded`] to obtain a handle to a library that
/// must already be loaded. There is no portable equivalent for all UNIX targets. Users who do not
/// care about portability across UNIX platforms may use [`os::unix::Library::open`] with
/// `libc::RTLD_NOLOAD`;
///
/// [`os::windows::Library::open_already_loaded`]: crate::os::windows::Library::open_already_loaded
/// [`os::unix::Library::open`]: crate::os::unix::Library::open
pub mod r0_6_7 {}

/// Release 0.6.6 (2020-12-03)
///
/// * Fix a double-release of resources when [`Library::close`] or [`os::windows::Library::close`]
///   is used on Windows.
///
/// [`Library::close`]: crate::Library::close
/// [`os::windows::Library::close`]: crate::os::windows::Library::close
pub mod r0_6_6 {}

/// Release 0.6.5 (2020-10-23)
///
/// * Upgrade cfg-if 0.1 to 1.0
pub mod r0_6_5 {}

/// Release 0.6.4 (2020-10-10)
///
/// * Remove use of `build.rs` making it easier to build `libloading` without cargo. It also
///   almost halves the build time of this crate.
pub mod r0_6_4 {}

/// Release 0.6.3 (2020-08-22)
///
/// * Improve documentation, allowing to view all of the os-specific functionality from
/// documentation generated for any target;
/// * Add [`os::windows::Library::this`];
/// * Added constants to use with OS-specific `Library::open`;
/// * Add [`library_filename`].
///
/// [`os::windows::Library::this`]: crate::os::windows::Library::this
/// [`library_filename`]: crate::library_filename
pub mod r0_6_3 {}

/// Release 0.6.2 (2020-05-06)
///
/// * Fixed building of this library on Illumos.
pub mod r0_6_2 {}

/// Release 0.6.1 (2020-04-15)
///
/// * Introduced a new method [`os::windows::Library::load_with_flags`];
/// * Added support for the Illumos triple.
///
/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
pub mod r0_6_1 {}

/// Release 0.6.0 (2020-04-05)
///
/// * Introduced a new method [`os::unix::Library::get_singlethreaded`];
/// * Added (untested) support for building when targetting Redox and Fuchsia;
/// * The APIs exposed by this library no longer panic and instead return an `Err` when it used
///   to panic.
///
/// ## Breaking changes
///
/// * Minimum required (stable) version of Rust to build this library is now 1.40.0;
/// * This crate now implements a custom [`Error`] type and all APIs now return this type rather
///   than returning the `std::io::Error`;
/// * `libloading::Result` has been removed;
/// * Removed the dependency on the C compiler to build this library on UNIX-like platforms.
///   `libloading` used to utilize a snippet written in C to work-around the unlikely possibility
///   of the target having a thread-unsafe implementation of the `dlerror` function. The effect of
///   the work-around was very opportunistic: it would not work if the function was called by
///   forgoing `libloading`.
///
///   Starting with 0.6.0, [`Library::get`] on platforms where `dlerror` is not MT-safe (such as
///   FreeBSD, DragonflyBSD or NetBSD) will unconditionally return an error when the underlying
///   `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
///   consider using [`os::unix::Library::get_singlethreaded`] instead.
///
/// [`Library::get`]: crate::Library::get
/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
/// [`Error`]: crate::Error
pub mod r0_6_0 {}

/// Release 0.5.2 (2019-07-07)
///
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
pub mod r0_5_2 {}

/// Release 0.5.1 (2019-06-01)
///
/// * Build on Haiku targets.
pub mod r0_5_1 {}

/// Release 0.5.0 (2018-01-11)
///
/// * Update to `winapi = ^0.3`;
///
/// ## Breaking changes
///
/// * libloading now requires a C compiler to build on UNIX;
///   * This is a temporary measure until the [`linkage`] attribute is stabilised;
///   * Necessary to resolve [#32].
///
/// [`linkage`]: https://github.com/rust-lang/rust/issues/29603
/// [#32]: https://github.com/nagisa/rust_libloading/issues/32
pub mod r0_5_0 {}

/// Release 0.4.3 (2017-12-07)
///
/// * Bump lazy-static dependency to `^1.0`;
/// * `cargo test --release` now works when testing libloading.
pub mod r0_4_3 {}

/// Release 0.4.2 (2017-09-24)
///
/// * Improved error and race-condition handling on Windows;
/// * Improved documentation about thread-safety of Library;
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
pub mod r0_4_2 {}

/// Release 0.4.1 (2017-08-29)
///
/// * Solaris support
pub mod r0_4_1 {}

/// Release 0.4.0 (2017-05-01)
///
/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
/// * Require at least version 1.14.0 of rustc to build;
///   * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
///     is what’s being required from now on.
pub mod r0_4_0 {}

/// Release 0.3.4 (2017-03-25)
///
/// * Remove rogue println!
pub mod r0_3_4 {}

/// Release 0.3.3 (2017-03-25)
///
/// * Panics when `Library::get` is called for incompatibly sized type such as named function
///   types (which are zero-sized).
pub mod r0_3_3 {}

/// Release 0.3.2 (2017-02-10)
///
/// * Minimum version required is now rustc 1.12.0;
/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
pub mod r0_3_2 {}

/// Release 0.3.1 (2016-10-01)
///
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
pub mod r0_3_1 {}

/// Release 0.3.0 (2016-07-27)
///
/// * Greatly improved documentation, especially around platform-specific behaviours;
/// * Improved test suite by building our own library to test against;
/// * All `Library`-ies now implement `Send`.
/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
/// wrapper into unsafe `os::platform::Symbol`.
///
/// The last two additions focus on not restricting potential usecases of this library, allowing
/// users of the library to circumvent safety checks if need be.
///
/// ## Breaking Changes
///
/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
/// whereas now the call to `Library::new` will return an error signifying presence of such error.
///
/// ## os::platform
/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
/// ordinal number;
pub mod r0_3_0 {}
<commit_msg>Adjust the date of the release in changelog<commit_after>//! The change log.

/// Release 0.7.0 (2021-02-06)
///
/// ## Breaking changes
///
/// ### Loading functions are now `unsafe`
///
/// A number of associated methods involved in loading a library were changed to
/// be `unsafe`. The affected functions are: [`Library::new`], [`os::unix::Library::new`],
/// [`os::unix::Library::open`], [`os::windows::Library::new`],
/// [`os::windows::Library::load_with_flags`]. This is the most prominent breaking change in this
/// release and affects majority of the users of `libloading`.
///
/// In order to see why it was necessary, consider the following snippet of C++ code:
///
/// ```c++
/// #include <vector>
/// #include <iostream>
///
/// static std::vector<unsigned int> UNSHUU = { 1, 2, 3 };
///
/// int main() {
///     std::cout << UNSHUU[0] << UNSHUU[1] << UNSHUU[2] << std::endl; // Prints 123
///     return 0;
/// }
/// ```
///
/// The `std::vector` type, much like in Rust's `Vec`, stores its contents in a buffer allocated on
/// the heap. In this example the vector object itself is stored and initialized as a static
/// variable – a compile time construct. The heap, on the other hand, is a runtime construct. And
/// yet the code works exactly as you'd expect – the vector contains numbers 1, 2 and 3 stored in
/// a buffer on heap. So, _what_ makes it work out, exactly?
///
/// Various executable and shared library formats define conventions and machinery to execute
/// arbitrary code when a program or a shared library is loaded. On systems using the PE format
/// (e.g. Windows) this is available via the optional `DllMain` initializer. Various systems
/// utilizing the ELF format take a sightly different approach of maintaining an array of function
/// pointers in the `.init_array` section. A very similar mechanism exists on systems that utilize
/// the Mach-O format.
///
/// For the C++ program above, the object stored in the `UNSHUU` global variable is constructed
/// by code run as part of such an initializer routine. This initializer is run before the entry
/// point (the `main` function) is executed, allowing for this magical behaviour to be possible.
/// Were the C++ code built as a shared library instead, the initialization routines would run as
/// the resulting shared library is loaded. In case of `libloading` – during the call to
/// `Library::new` and other methods affected by this change.
///
/// These initialization (and very closely related termination) routines can be utilized outside of
/// C++ too. Anybody can build a shared library in variety of different programming languages and
/// set up the initializers to execute arbitrary code. Potentially code that does all sorts of
/// wildly unsound stuff.
///
/// The routines are executed by components that are an integral part of the operating system.
/// Changing or controlling the operation of these components is infeasible. With that in
/// mind, the initializer and termination routines are something anybody loading a library must
/// carefully evaluate the libraries loaded for soundness.
///
/// In practice, a vast majority of the libraries can be considered a good citizen and their
/// initialization and termination routines, if they have any at all, can be trusted to be sound.
///
/// Also see: [issue #86].
///
/// ### Better & more consistent default behaviour on UNIX systems
///
/// On UNIX systems the [`Library::new`], [`os::unix::Library::new`] and
/// [`os::unix::Library::this`] methods have been changed to use
/// [RTLD_LAZY] | [RTLD_LOCAL] as the default set of loader options (previously:
/// [`RTLD_NOW`]). This has a couple benefits. Namely:
///
/// * Lazy binding is generally quicker to execute when only a subset of symbols from a library are
///   used and is typically the default when neither `RTLD_LAZY` nor `RTLD_NOW` are specified when
///   calling the underlying `dlopen` API;
/// * On most UNIX systems (macOS being a notable exception) `RTLD_LOCAL` is the default when
///   neither `RTLD_LOCAL` nor [`RTLD_GLOBAL`] are specified. The explicit setting of the
///   `RTLD_LOCAL` flag makes this behaviour consistent across platforms.
///
/// ### Dropped support for Windows XP/Vista
///
/// The (broken) support for Windows XP and Windows Vista environments was removed. This was
/// prompted primarily by a similar policy change in the [Rust
/// project](https://github.com/rust-lang/compiler-team/issues/378) but also as an acknowledgement
/// to the fact that `libloading` never worked in these environments anyway.
///
/// ### More accurate error variant names
///
/// Finally, the `Error::LoadLibraryW` renamed to [`Error::LoadLibraryExW`] to more accurately
/// represent the underlying API that's failing. No functional changes as part of this rename
/// intended.
///
/// [issue #86]: https://github.com/nagisa/rust_libloading/issues/86
/// [`Library::new`]: crate::Library::new
/// [`Error::LoadLibraryExW`]: crate::Error::LoadLibraryExW
/// [`os::unix::Library::this`]: crate::os::unix::Library::this
/// [`os::unix::Library::new`]: crate::os::unix::Library::new
/// [`os::unix::Library::open`]: crate::os::unix::Library::new
/// [`os::windows::Library::new`]: crate::os::windows::Library::new
/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
/// [`RTLD_NOW`]: crate::os::unix::RTLD_NOW
/// [RTLD_LAZY]: crate::os::unix::RTLD_LAZY
/// [RTLD_LOCAL]: crate::os::unix::RTLD_LOCAL
/// [`RTLD_GLOBAL`]: crate::os::unix::RTLD_GLOBAL
pub mod r0_7_0 {}

/// Release 0.6.7 (2021-01-14)
///
/// * Added a [`os::windows::Library::open_already_loaded`] to obtain a handle to a library that
/// must already be loaded. There is no portable equivalent for all UNIX targets. Users who do not
/// care about portability across UNIX platforms may use [`os::unix::Library::open`] with
/// `libc::RTLD_NOLOAD`;
///
/// [`os::windows::Library::open_already_loaded`]: crate::os::windows::Library::open_already_loaded
/// [`os::unix::Library::open`]: crate::os::unix::Library::open
pub mod r0_6_7 {}

/// Release 0.6.6 (2020-12-03)
///
/// * Fix a double-release of resources when [`Library::close`] or [`os::windows::Library::close`]
///   is used on Windows.
///
/// [`Library::close`]: crate::Library::close
/// [`os::windows::Library::close`]: crate::os::windows::Library::close
pub mod r0_6_6 {}

/// Release 0.6.5 (2020-10-23)
///
/// * Upgrade cfg-if 0.1 to 1.0
pub mod r0_6_5 {}

/// Release 0.6.4 (2020-10-10)
///
/// * Remove use of `build.rs` making it easier to build `libloading` without cargo. It also
///   almost halves the build time of this crate.
pub mod r0_6_4 {}

/// Release 0.6.3 (2020-08-22)
///
/// * Improve documentation, allowing to view all of the os-specific functionality from
/// documentation generated for any target;
/// * Add [`os::windows::Library::this`];
/// * Added constants to use with OS-specific `Library::open`;
/// * Add [`library_filename`].
///
/// [`os::windows::Library::this`]: crate::os::windows::Library::this
/// [`library_filename`]: crate::library_filename
pub mod r0_6_3 {}

/// Release 0.6.2 (2020-05-06)
///
/// * Fixed building of this library on Illumos.
pub mod r0_6_2 {}

/// Release 0.6.1 (2020-04-15)
///
/// * Introduced a new method [`os::windows::Library::load_with_flags`];
/// * Added support for the Illumos triple.
///
/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags
pub mod r0_6_1 {}

/// Release 0.6.0 (2020-04-05)
///
/// * Introduced a new method [`os::unix::Library::get_singlethreaded`];
/// * Added (untested) support for building when targetting Redox and Fuchsia;
/// * The APIs exposed by this library no longer panic and instead return an `Err` when it used
///   to panic.
///
/// ## Breaking changes
///
/// * Minimum required (stable) version of Rust to build this library is now 1.40.0;
/// * This crate now implements a custom [`Error`] type and all APIs now return this type rather
///   than returning the `std::io::Error`;
/// * `libloading::Result` has been removed;
/// * Removed the dependency on the C compiler to build this library on UNIX-like platforms.
///   `libloading` used to utilize a snippet written in C to work-around the unlikely possibility
///   of the target having a thread-unsafe implementation of the `dlerror` function. The effect of
///   the work-around was very opportunistic: it would not work if the function was called by
///   forgoing `libloading`.
///
///   Starting with 0.6.0, [`Library::get`] on platforms where `dlerror` is not MT-safe (such as
///   FreeBSD, DragonflyBSD or NetBSD) will unconditionally return an error when the underlying
///   `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
///   consider using [`os::unix::Library::get_singlethreaded`] instead.
///
/// [`Library::get`]: crate::Library::get
/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
/// [`Error`]: crate::Error
pub mod r0_6_0 {}

/// Release 0.5.2 (2019-07-07)
///
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
pub mod r0_5_2 {}

/// Release 0.5.1 (2019-06-01)
///
/// * Build on Haiku targets.
pub mod r0_5_1 {}

/// Release 0.5.0 (2018-01-11)
///
/// * Update to `winapi = ^0.3`;
///
/// ## Breaking changes
///
/// * libloading now requires a C compiler to build on UNIX;
///   * This is a temporary measure until the [`linkage`] attribute is stabilised;
///   * Necessary to resolve [#32].
///
/// [`linkage`]: https://github.com/rust-lang/rust/issues/29603
/// [#32]: https://github.com/nagisa/rust_libloading/issues/32
pub mod r0_5_0 {}

/// Release 0.4.3 (2017-12-07)
///
/// * Bump lazy-static dependency to `^1.0`;
/// * `cargo test --release` now works when testing libloading.
pub mod r0_4_3 {}

/// Release 0.4.2 (2017-09-24)
///
/// * Improved error and race-condition handling on Windows;
/// * Improved documentation about thread-safety of Library;
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
pub mod r0_4_2 {}

/// Release 0.4.1 (2017-08-29)
///
/// * Solaris support
pub mod r0_4_1 {}

/// Release 0.4.0 (2017-05-01)
///
/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
/// * Require at least version 1.14.0 of rustc to build;
///   * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
///     is what’s being required from now on.
pub mod r0_4_0 {}

/// Release 0.3.4 (2017-03-25)
///
/// * Remove rogue println!
pub mod r0_3_4 {}

/// Release 0.3.3 (2017-03-25)
///
/// * Panics when `Library::get` is called for incompatibly sized type such as named function
///   types (which are zero-sized).
pub mod r0_3_3 {}

/// Release 0.3.2 (2017-02-10)
///
/// * Minimum version required is now rustc 1.12.0;
/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
pub mod r0_3_2 {}

/// Release 0.3.1 (2016-10-01)
///
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
pub mod r0_3_1 {}

/// Release 0.3.0 (2016-07-27)
///
/// * Greatly improved documentation, especially around platform-specific behaviours;
/// * Improved test suite by building our own library to test against;
/// * All `Library`-ies now implement `Send`.
/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
/// wrapper into unsafe `os::platform::Symbol`.
///
/// The last two additions focus on not restricting potential usecases of this library, allowing
/// users of the library to circumvent safety checks if need be.
///
/// ## Breaking Changes
///
/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
/// whereas now the call to `Library::new` will return an error signifying presence of such error.
///
/// ## os::platform
/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
/// ordinal number;
pub mod r0_3_0 {}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error;

use super::row::{Row, RowError};
use super::schema::{Schema, Type};
use super::field::Field;

#[derive(Debug)]
pub enum StreamError {
    ValidationError(String),
    FieldNotFound(String),
    MissingRowId
}

impl From<RowError> for StreamError {
    fn from(err: RowError) -> StreamError {
        StreamError::MissingRowId
    }

}

pub struct RowBuilder {
    data: HashMap<String, Field>,
}

impl RowBuilder {
    fn new() -> RowBuilder {
        RowBuilder{data:HashMap::new()}
    }
    fn set_string(&mut self, key: &str, val: &str) -> &mut RowBuilder {
        self.data.insert(key.to_string(), Field::String(val.to_string()));
        self
    }
    fn set_int(&mut self, key: &str, val: i64) -> &mut RowBuilder {
        self.data.insert(key.to_string(), Field::Int(val));
        self
    }
}

#[derive(Debug)]
pub struct Stream {
    max_id: u64,
    inserts: u64,
    ttl: Option<u64>,
    rows: Vec<Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream::new_empty();
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    // used in temporary tables
    pub fn new_empty() -> Stream {
        let mut stream = Stream {
            max_id: 0,
            inserts: 0,
            rows: Vec::new(),
            schema: Schema::new(),
            ttl: None,
        };
        stream
    }

    /* we take a HashMap of String -> Field here
    * we're going to convert it to HashMap<u8, Field> for the Row struct
    */
    pub fn insert(&mut self, mut row_builder: RowBuilder) -> Result<Row, StreamError> {
        // validate the inserted data
        let mut row_map : HashMap<u8, Field> = HashMap::new();
        for (key, val) in row_builder.data.drain() {
            // get the field from the schema
            // TypeDef
            let tmp = try!(self.schema.get(&key)
                               .ok_or(StreamError::FieldNotFound(key.to_string())));
            row_map.insert(tmp.id, val);

        }
        let row = try!(Row::new(row_map));
        self.rows.push(row.clone());
        self.inserts += 1;
        Ok(row)
    }

    fn scan(&self) -> Result<Stream, StreamError> {
        Ok(Stream::new())
    }

}

#[cfg(test)]
mod tests {
    use super::{Stream, RowBuilder};
    use super::super::schema::{Schema, Type};
    use super::super::field::Field;
    use std::collections::HashMap;

    fn get_stream() -> Stream {
        let mut s = Stream::new();
        s.schema.add_type("name", Type::String);
        s.schema.add_type("age", Type::Int);
        s.schema.add_type("created", Type::Timestamp);
        s

    }

    #[test]
    fn test_insert_works_normal_case() {
        let mut s = Stream::new();
        s.schema.add_type("name", Type::String);

        let mut row = RowBuilder::new();
        row.set_string("name", "test");
        let result = s.insert(row).unwrap();
        assert_eq!(s.inserts, 1);
        // was the data inserted?

    }

    fn test_builder() {
        let mut s = get_stream();
        let mut row = RowBuilder::new();

        row.set_string("name", "value")
           .set_int("age", 10);
        s.insert(row);
    }
}<commit_msg>moved data to hashmap<commit_after>use std::collections::HashMap;
use std::error;

use super::row::{Row, RowError};
use super::schema::{Schema, Type};
use super::field::Field;

#[derive(Debug)]
pub enum StreamError {
    ValidationError(String),
    FieldNotFound(String),
    MissingRowId
}

impl From<RowError> for StreamError {
    fn from(err: RowError) -> StreamError {
        StreamError::MissingRowId
    }

}

pub struct RowBuilder {
    data: HashMap<String, Field>,
}

impl RowBuilder {
    fn new() -> RowBuilder {
        RowBuilder{data:HashMap::new()}
    }
    fn set_string(&mut self, key: &str, val: &str) -> &mut RowBuilder {
        self.data.insert(key.to_string(), Field::String(val.to_string()));
        self
    }
    fn set_int(&mut self, key: &str, val: i64) -> &mut RowBuilder {
        self.data.insert(key.to_string(), Field::Int(val));
        self
    }
}

#[derive(Debug)]
pub struct Stream {
    inserts: u64,
    ttl: Option<u64>,
    rows: HashMap<u64, Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream::new_empty();
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    // used in temporary tables
    pub fn new_empty() -> Stream {
        let mut stream = Stream {
            inserts: 0,
            rows: HashMap::new(),
            schema: Schema::new(),
            ttl: None,
        };
        stream
    }

    /* we take a HashMap of String -> Field here
    * we're going to convert it to HashMap<u8, Field> for the Row struct
    */
    pub fn insert(&mut self, mut row_builder: RowBuilder) -> Result<Row, StreamError> {
        // validate the inserted data
        let mut row_map : HashMap<u8, Field> = HashMap::new();
        for (key, val) in row_builder.data.drain() {
            // get the field from the schema
            // TypeDef
            let tmp = try!(self.schema.get(&key)
                               .ok_or(StreamError::FieldNotFound(key.to_string())));
            row_map.insert(tmp.id, val);

        }
        let row = try!(Row::new(row_map));
        self.rows.insert(self.inserts, row.clone());
        self.inserts += 1;
        Ok(row)
    }

    fn scan(&self) -> Result<Stream, StreamError> {
        Ok(Stream::new())
    }

}

#[cfg(test)]
mod tests {
    use super::{Stream, RowBuilder};
    use super::super::schema::{Schema, Type};
    use super::super::field::Field;
    use std::collections::HashMap;

    fn get_stream() -> Stream {
        let mut s = Stream::new();
        s.schema.add_type("name", Type::String);
        s.schema.add_type("age", Type::Int);
        s.schema.add_type("created", Type::Timestamp);
        s

    }

    #[test]
    fn test_insert_works_normal_case() {
        let mut s = Stream::new();
        s.schema.add_type("name", Type::String);

        let mut row = RowBuilder::new();
        row.set_string("name", "test");
        let result = s.insert(row).unwrap();
        assert_eq!(s.inserts, 1);
        // was the data inserted?

    }

    fn test_builder() {
        let mut s = get_stream();
        let mut row = RowBuilder::new();

        row.set_string("name", "value")
           .set_int("age", 10);
        s.insert(row);
    }
}<|endoftext|>