<commit_before>use std::io::prelude::*;
use std::io;
use std::fs::File;
use bit_vec::BitVec;

pub fn usize_from_file(path: &str) -> Result<usize, &'static str> {
    if let Ok(s) = string_from_file(path) {
        if let Ok(i) = s.trim().parse() {
            Ok(i)
        } else {
            Err("Unable to parse")
        }
    } else {
        Err("Unable to open file")
    }
}

fn string_from_file(path: &str) -> Result<String, io::Error> {
    match File::open(&path) {
        Ok(mut f) => {
            let mut s = String::new();
            match f.read_to_string(&mut s) {
                Ok(_) => Ok(s),
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(e),
    }
}

pub fn bitmask_from_hex_file(path: &str) -> Result<BitVec, &'static str> {
    if let Ok(s) = string_from_file(path) {
        bitmask_from_hex(&s)
    } else {
        Err("Error reading file")
    }
}

pub fn bytes_from_hex(hex: &str) -> Result<Vec<u8>, &'static str> {
    let mut bytes = Vec::<u8>::new();
    let mut chars =  Vec::<char>::new();
    for c in hex.trim().chars() {
        // skip common delimiters
        match c {
            ',' | ' ' | '_' => continue,
            _ => {}
        }
        chars.push(c);
    }
    for chunk in chars.chunks(2) {
        let string = format!("{}{}", chunk[0], chunk[1]);
        if let Ok(byte) = u8::from_str_radix(&string.to_string(), 16) {
            bytes.push(byte);
        } else {
            return Err("Failure parsing hex string");
        }
    }
    Ok(bytes)
}

pub fn bitmask_from_hex(hex: &str) -> Result<BitVec, &'static str> {
    match bytes_from_hex(hex) {
        Ok(bytes) => Ok(BitVec::from_bytes(&bytes)),
        Err(e) => Err(e),
    }
}
<commit_msg>add a test and actually fix the function<commit_after>use std::io::prelude::*;
use std::io;
use std::fs::File;
use bit_vec::BitVec;

pub fn usize_from_file(path: &str) -> Result<usize, &'static str> {
    if let Ok(s) = string_from_file(path) {
        if let Ok(i) = s.trim().parse() {
            Ok(i)
        } else {
            Err("Unable to parse")
        }
    } else {
        Err("Unable to open file")
    }
}

fn string_from_file(path: &str) -> Result<String, io::Error> {
    match File::open(&path) {
        Ok(mut f) => {
            let mut s = String::new();
            match f.read_to_string(&mut s) {
                Ok(_) => Ok(s),
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(e),
    }
}

pub fn bitmask_from_hex_file(path: &str) -> Result<BitVec, &'static str> {
    if let Ok(s) = string_from_file(path) {
        bitmask_from_hex(&s)
    } else {
        Err("Error reading file")
    }
}

/// parse a hex string to bytes_from_hex
///
/// # Examples
///
/// ```
/// use sysfs_rs::util;
///
/// assert_eq!(util::bytes_from_hex("00"), Ok(vec![0]));
/// assert_eq!(util::bytes_from_hex("0"), Ok(vec![0]));
/// assert_eq!(util::bytes_from_hex("f"), Ok(vec![240]));
/// assert_eq!(util::bytes_from_hex("F"), Ok(vec![240]));
/// assert_eq!(util::bytes_from_hex("FF"), Ok(vec![255]));
/// ```
pub fn bytes_from_hex(hex: &str) -> Result<Vec<u8>, &'static str> {
    let mut bytes = Vec::<u8>::new();
    let mut chars = Vec::<char>::new();
    for c in hex.trim().chars() {
        // skip common delimiters
        match c {
            ',' | ' ' | '_' => continue,
            _ => {}
        }
        chars.push(c);
    }
    for chunk in chars.chunks(2) {
        let string = if chunk.len() == 1 {
            format!("{}0", chunk[0])
        } else {
            format!("{}{}", chunk[0], chunk[1])
        };

        if let Ok(byte) = u8::from_str_radix(&string.to_string(), 16) {
            bytes.push(byte);
        } else {
            return Err("Failure parsing hex string");
        }
    }
    Ok(bytes)
}

pub fn bitmask_from_hex(hex: &str) -> Result<BitVec, &'static str> {
    match bytes_from_hex(hex) {
        Ok(bytes) => Ok(BitVec::from_bytes(&bytes)),
        Err(e) => Err(e),
    }
}
<|endoftext|>


<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(), "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
}
<commit_msg>disable hover<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 parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        } else if self.next_ws.is_some() {
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.writeln("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn impl_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn struct_impl(&mut self, ast: &syn::DeriveInput, path: &str,
                   blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} {}{} {{", anno, ast.ident.as_ref(),
                              anno));
        self.indent();

        self.handle(blocks);

        if let Some(nodes) = nodes {
            let trait_name = format!("TraitFrom{}", path_as_identifier(path));
            self.writeln(&format!("fn render_trait_to(&self, timpl: &{},",
                                  trait_name));
            self.writeln("                   writer: &mut std::fmt::Write) {");
            self.indent();
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
            self.dedent();
            self.writeln("}");
        }

        self.dedent();
        self.writeln("}");
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  block_names: &[&str]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
                bname));
            self.indent();
            self.writeln(&format!("self.impl_block_{}_to(writer);", bname));
            self.dedent();
            self.writeln("}");
        }

        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        self.writeln(&format!("trait TraitFrom{} {{",
                              path_as_identifier(path)));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        if base.is_none() {
            gen.struct_impl(ast, path, &blocks, Some(&content));
            gen.define_trait(path, &block_names);
        } else {
            gen.struct_impl(ast, path, &blocks, None);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        gen.impl_trait(ast, tmpl_path, &block_names);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<commit_msg>Remove some useless cruft<commit_after>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.writeln("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn impl_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn struct_impl(&mut self, ast: &syn::DeriveInput, path: &str,
                   blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} {}{} {{", anno, ast.ident.as_ref(),
                              anno));
        self.indent();

        self.handle(blocks);

        if let Some(nodes) = nodes {
            let trait_name = format!("TraitFrom{}", path_as_identifier(path));
            self.writeln(&format!("fn render_trait_to(&self, timpl: &{},",
                                  trait_name));
            self.writeln("                   writer: &mut std::fmt::Write) {");
            self.indent();
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
            self.dedent();
            self.writeln("}");
        }

        self.dedent();
        self.writeln("}");
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  block_names: &[&str]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
                bname));
            self.indent();
            self.writeln(&format!("self.impl_block_{}_to(writer);", bname));
            self.dedent();
            self.writeln("}");
        }

        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        self.writeln(&format!("trait TraitFrom{} {{",
                              path_as_identifier(path)));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        if base.is_none() {
            gen.struct_impl(ast, path, &blocks, Some(&content));
            gen.define_trait(path, &block_names);
        } else {
            gen.struct_impl(ast, path, &blocks, None);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        gen.impl_trait(ast, tmpl_path, &block_names);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<|endoftext|>


<commit_before>//! This package was automatically generated with [`rust-bindgen`][1] and as such was not
//! user-generated.
//!
//! The functions contained are expected to be used with [`fitsio`][2], a high level API wrapper
//! around the low level direct C-bindings, though the bindings are complete enough to be usable.
//!
//! This code will not be directly documented, and so users should refer to the [`fitsio` C
//! documentation][3] for usage.
//!
//! ## Note about function names
//!
//! Unfortunately we must use fits short names throughout. The C-api exposes long names for
//! functions which are more descriptive, for example `fits_open_file` instead of `ffopen`, but the
//! symbols available in the library have only short names, and the long names are merely
//! preprocessor definitions.
//!
//! ## Examples
//!
//! ```rust
//! # extern crate fitsio_sys;
//! use std::ptr;
//! use std::ffi;
//! # use fitsio_sys::{ffinit, ffphps, ffclos};
//!
//! # fn main() {
//! let filename = ffi::CString::new("!/tmp/test.fits").unwrap();
//! let mut fptr = ptr::null_mut();
//! let mut status = 0;
//!
//! unsafe {
//!     // Create a new file, clobbering any pre-existing file
//!     ffinit(&mut fptr as *mut *mut _,
//!         filename.as_ptr(),
//!         &mut status);
//!
//!     // Add an empty primary HDU
//!     ffphps(fptr, 8, 0, ptr::null_mut(), &mut status);
//!
//!     // Finally close the file
//!     ffclos(fptr, &mut status);
//! }
//!
//! assert_eq!(status, 0);
//! # }
//! ```
//!
//! [1]: https://github.com/servo/rust-bindgen
//! [2]: https://crates.io/crates/fitsio
//! [3]: http://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/cfitsio.html

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(improper_ctypes)]

extern crate libc;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod test {
    extern crate tempdir;

    use std::ffi;
    use std::ptr;
    use libc::c_char;
    use super::*;

    #[test]
    fn raw_opening_an_existing_file() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffclos(fptr, &mut status);
        }

        assert_eq!(status, 0);
    }

    #[test]
    fn raw_creating_a_new_file() {
        // Set up the test filename
        let tdir = tempdir::TempDir::new("rust-fitsio-").unwrap();
        let filename = tdir.path().join("test.fits");
        assert!(!filename.exists());

        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename.to_str().unwrap()).unwrap();

        unsafe {
            ffinit(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   &mut status);
        }

        assert!(filename.exists());
    }

    #[test]
    fn getting_current_hdu_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();
        let mut hdu_num = -1;

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 1);
    }

    #[test]
    fn changing_hdu_by_absolute_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut hdu_type = 0;
        let mut hdu_num = 0;

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffmahd(fptr, 2, &mut hdu_type, &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 2);
    }

    #[test]
    fn reading_header_key_value() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut long_value = 0;
        let mut float_value = 0.0;
        let mut double_value = 0.0;
        let keyname = ffi::CString::new("INTTEST").unwrap();
        let double_keyname = ffi::CString::new("DBLTEST").unwrap();
        let mut comment: Vec<c_char> = vec![0; 73];
        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffgkyj(fptr,
                   keyname.as_ptr(),
                   &mut long_value,
                   ptr::null_mut(),
                   &mut status);
            ffgkye(fptr,
                   keyname.as_ptr(),
                   &mut float_value,
                   ptr::null_mut(),
                   &mut status);

            // Double version is different
            ffgkyd(fptr,
                   double_keyname.as_ptr(),
                   &mut double_value,
                   comment.as_mut_ptr(),
                   &mut status);
            ffclos(fptr, &mut status);
        }

        assert_eq!(long_value, 42);
        assert_eq!(float_value, 42.0);
        assert_eq!(double_value, 3. / 32.);

        // TODO Hacky way of getting a string out. This should be simplified.
        let comment: Vec<u8> = comment.iter().map(|&x| x as u8).filter(|&x| x != 0).collect();
        let comment = String::from_utf8(comment).unwrap();
        assert_eq!(comment, "Double value");
    }

    // #[test]
    // fn api_usage() {
    // use fitsio::FitsFile;
    //
    // let mut f = FitsFile::open("../testdata/full_example.fits");
    // let mut primary_hdu = f.primary_hdu();
    // let header = primary_hdu.header();
    // let exposure_time: f32 = header["exposure"];
    // }
    //
}
<commit_msg>Update documentation tests<commit_after>//! This package was automatically generated with [`rust-bindgen`][1] and as such was not
//! user-generated.
//!
//! The functions contained are expected to be used with [`fitsio`][2], a high level API wrapper
//! around the low level direct C-bindings, though the bindings are complete enough to be usable.
//!
//! This code will not be directly documented, and so users should refer to the [`fitsio` C
//! documentation][3] for usage.
//!
//! ## Note about function names
//!
//! Unfortunately we must use fits short names throughout. The C-api exposes long names for
//! functions which are more descriptive, for example `fits_open_file` instead of `ffopen`, but the
//! symbols available in the library have only short names, and the long names are merely
//! preprocessor definitions.
//!
//! ## Examples
//!
//! ```rust
//! # extern crate fitsio_sys_bindgen as fitsio_sys;
//! use std::ptr;
//! use std::ffi;
//! # use fitsio_sys::{ffinit, ffphps, ffclos};
//!
//! # fn main() {
//! let filename = ffi::CString::new("!/tmp/test.fits").unwrap();
//! let mut fptr = ptr::null_mut();
//! let mut status = 0;
//!
//! unsafe {
//!     // Create a new file, clobbering any pre-existing file
//!     ffinit(&mut fptr as *mut *mut _,
//!         filename.as_ptr(),
//!         &mut status);
//!
//!     // Add an empty primary HDU
//!     ffphps(fptr, 8, 0, ptr::null_mut(), &mut status);
//!
//!     // Finally close the file
//!     ffclos(fptr, &mut status);
//! }
//!
//! assert_eq!(status, 0);
//! # }
//! ```
//!
//! [1]: https://github.com/servo/rust-bindgen
//! [2]: https://crates.io/crates/fitsio
//! [3]: http://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/cfitsio.html

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(improper_ctypes)]

extern crate libc;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod test {
    extern crate tempdir;

    use std::ffi;
    use std::ptr;
    use libc::c_char;
    use super::*;

    #[test]
    fn raw_opening_an_existing_file() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffclos(fptr, &mut status);
        }

        assert_eq!(status, 0);
    }

    #[test]
    fn raw_creating_a_new_file() {
        // Set up the test filename
        let tdir = tempdir::TempDir::new("rust-fitsio-").unwrap();
        let filename = tdir.path().join("test.fits");
        assert!(!filename.exists());

        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename.to_str().unwrap()).unwrap();

        unsafe {
            ffinit(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   &mut status);
        }

        assert!(filename.exists());
    }

    #[test]
    fn getting_current_hdu_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();
        let mut hdu_num = -1;

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 1);
    }

    #[test]
    fn changing_hdu_by_absolute_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut hdu_type = 0;
        let mut hdu_num = 0;

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffmahd(fptr, 2, &mut hdu_type, &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 2);
    }

    #[test]
    fn reading_header_key_value() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut long_value = 0;
        let mut float_value = 0.0;
        let mut double_value = 0.0;
        let keyname = ffi::CString::new("INTTEST").unwrap();
        let double_keyname = ffi::CString::new("DBLTEST").unwrap();
        let mut comment: Vec<c_char> = vec![0; 73];
        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
            ffgkyj(fptr,
                   keyname.as_ptr(),
                   &mut long_value,
                   ptr::null_mut(),
                   &mut status);
            ffgkye(fptr,
                   keyname.as_ptr(),
                   &mut float_value,
                   ptr::null_mut(),
                   &mut status);

            // Double version is different
            ffgkyd(fptr,
                   double_keyname.as_ptr(),
                   &mut double_value,
                   comment.as_mut_ptr(),
                   &mut status);
            ffclos(fptr, &mut status);
        }

        assert_eq!(long_value, 42);
        assert_eq!(float_value, 42.0);
        assert_eq!(double_value, 3. / 32.);

        // TODO Hacky way of getting a string out. This should be simplified.
        let comment: Vec<u8> = comment.iter().map(|&x| x as u8).filter(|&x| x != 0).collect();
        let comment = String::from_utf8(comment).unwrap();
        assert_eq!(comment, "Double value");
    }

    // #[test]
    // fn api_usage() {
    // use fitsio::FitsFile;
    //
    // let mut f = FitsFile::open("../testdata/full_example.fits");
    // let mut primary_hdu = f.primary_hdu();
    // let header = primary_hdu.header();
    // let exposure_time: f32 = header["exposure"];
    // }
    //
}
<|endoftext|>


<commit_before>/**
   A parallel word-frequency counting program.

   This is meant primarily to demonstrate Rust's MapReduce framework.

   It takes a list of files on the command line and outputs a list of
   words along with how many times each word is used.

*/

// xfail-pretty

use std;

use option = option;
use option::Some;
use option::None;
use std::map;
use std::map::hashmap;
use io::WriterUtil;

use std::time;

use comm::Chan;
use comm::Port;
use comm::recv;
use comm::send;

macro_rules! move_out (
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
)

trait word_reader {
    fn read_word() -> Option<~str>;
}

trait hash_key {
    pure fn hash() -> uint;
    pure fn eq(&&k: self) -> bool;
}

impl ~str: hash_key {
    pure fn hash() -> uint { str::hash(&self) }
    pure fn eq(&&x: ~str) -> bool { self == x }
}

// These used to be in task, but they disappeard.
type joinable_task = Port<()>;
fn spawn_joinable(+f: fn~()) -> joinable_task {
    let p = Port();
    let c = Chan(p);
    do task::spawn() |move f| {
        f();
        c.send(());
    }
    p
}

fn join(t: joinable_task) {
    t.recv()
}

impl io::Reader: word_reader {
    fn read_word() -> Option<~str> { read_word(self) }
}

fn file_word_reader(filename: ~str) -> word_reader {
    match io::file_reader(&Path(filename)) {
      result::Ok(f) => { f as word_reader }
      result::Err(e) => { fail fmt!("%?", e) }
    }
}

fn map(f: fn~() -> word_reader, emit: map_reduce::putter<~str, int>) {
    let f = f();
    loop {
        match f.read_word() {
          Some(w) => { emit(w, 1); }
          None => { break; }
        }
    }
}

fn reduce(&&word: ~str, get: map_reduce::getter<int>) {
    let mut count = 0;

    loop { match get() { Some(_) => { count += 1; } None => { break; } } }

    io::println(fmt!("%s\t%?", word, count));
}

struct box<T> {
    mut contents: Option<T>,

    fn swap(f: fn(+T) -> T) {
        let mut tmp = None;
        self.contents <-> tmp;
        self.contents = Some(f(option::unwrap(tmp)));
    }

    fn unwrap() -> T {
        let mut tmp = None;
        self.contents <-> tmp;
        option::unwrap(tmp)
    }
}

fn box<T>(+x: T) -> box<T> {
    box {
        contents: Some(x)
    }
}

mod map_reduce {
    export putter;
    export getter;
    export mapper;
    export reducer;
    export map_reduce;

    type putter<K: Send, V: Send> = fn(K, V);

    type mapper<K1: Send, K2: Send, V: Send> = fn~(K1, putter<K2, V>);

    type getter<V: Send> = fn() -> Option<V>;

    type reducer<K: Copy Send, V: Copy Send> = fn~(K, getter<V>);

    enum ctrl_proto<K: Copy Send, V: Copy Send> {
        find_reducer(K, Chan<Chan<reduce_proto<V>>>),
        mapper_done
    }

    proto! ctrl_proto (
        open: send<K: Copy Send, V: Copy Send> {
            find_reducer(K) -> reducer_response<K, V>,
            mapper_done -> !
        }

        reducer_response: recv<K: Copy Send, V: Copy Send> {
            reducer(Chan<reduce_proto<V>>) -> open<K, V>
        }
    )

    enum reduce_proto<V: Copy Send> { emit_val(V), done, addref, release }

    fn start_mappers<K1: Copy Send, K2: Const Copy Send hash_key,
                     V: Copy Send>(
        map: mapper<K1, K2, V>,
        &ctrls: ~[ctrl_proto::server::open<K2, V>],
        inputs: ~[K1])
        -> ~[joinable_task]
    {
        let mut tasks = ~[];
        for inputs.each |i| {
            let (ctrl, ctrl_server) = ctrl_proto::init();
            let ctrl = box(ctrl);
            vec::push(tasks, spawn_joinable(|| map_task(map, ctrl, i) ));
            vec::push(ctrls, ctrl_server);
        }
        return tasks;
    }

    fn map_task<K1: Copy Send, K2: Const Copy Send hash_key, V: Copy Send>(
        map: mapper<K1, K2, V>,
        ctrl: box<ctrl_proto::client::open<K2, V>>,
        input: K1)
    {
        // log(error, "map_task " + input);
        let intermediates = map::hashmap();

        do map(input) |key, val| {
            let mut c = None;
            let found = intermediates.find(key);
            match found {
              Some(_c) => { c = Some(_c); }
              None => {
                do ctrl.swap |ctrl| {
                    let ctrl = ctrl_proto::client::find_reducer(ctrl, key);
                    match pipes::recv(ctrl) {
                      ctrl_proto::reducer(c_, ctrl) => {
                        c = Some(c_);
                        move_out!(ctrl)
                      }
                    }
                }
                intermediates.insert(key, c.get());
                send(c.get(), addref);
              }
            }
            send(c.get(), emit_val(val));
        }

        fn finish<K: Copy Send, V: Copy Send>(_k: K, v: Chan<reduce_proto<V>>)
        {
            send(v, release);
        }
        for intermediates.each_value |v| { send(v, release) }
        ctrl_proto::client::mapper_done(ctrl.unwrap());
    }

    fn reduce_task<K: Copy Send, V: Copy Send>(
        reduce: reducer<K, V>,
        key: K,
        out: Chan<Chan<reduce_proto<V>>>)
    {
        let p = Port();

        send(out, Chan(p));

        let mut ref_count = 0;
        let mut is_done = false;

        fn get<V: Copy Send>(p: Port<reduce_proto<V>>,
                             &ref_count: int, &is_done: bool)
           -> Option<V> {
            while !is_done || ref_count > 0 {
                match recv(p) {
                  emit_val(v) => {
                    // error!("received %d", v);
                    return Some(v);
                  }
                  done => {
                    // error!("all done");
                    is_done = true;
                  }
                  addref => { ref_count += 1; }
                  release => { ref_count -= 1; }
                }
            }
            return None;
        }

        reduce(key, || get(p, ref_count, is_done) );
    }

    fn map_reduce<K1: Copy Send, K2: Const Copy Send hash_key, V: Copy Send>(
        map: mapper<K1, K2, V>,
        reduce: reducer<K2, V>,
        inputs: ~[K1])
    {
        let mut ctrl = ~[];

        // This task becomes the master control task. It task::_spawns
        // to do the rest.

        let reducers = map::hashmap();
        let mut tasks = start_mappers(map, ctrl, inputs);
        let mut num_mappers = vec::len(inputs) as int;

        while num_mappers > 0 {
            let (_ready, message, ctrls) = pipes::select(ctrl);
            match option::unwrap(message) {
              ctrl_proto::mapper_done => {
                // error!("received mapper terminated.");
                num_mappers -= 1;
                ctrl = ctrls;
              }
              ctrl_proto::find_reducer(k, cc) => {
                let c;
                // log(error, "finding reducer for " + k);
                match reducers.find(k) {
                  Some(_c) => {
                    // log(error,
                    // "reusing existing reducer for " + k);
                    c = _c;
                  }
                  None => {
                    // log(error, "creating new reducer for " + k);
                    let p = Port();
                    let ch = Chan(p);
                    let r = reduce, kk = k;
                    vec::push(tasks,
                              spawn_joinable(|| reduce_task(r, kk, ch) ));
                    c = recv(p);
                    reducers.insert(k, c);
                  }
                }
                ctrl = vec::append_one(
                    ctrls,
                    ctrl_proto::server::reducer(move_out!(cc), c));
              }
            }
        }

        for reducers.each_value |v| { send(v, done) }

        for tasks.each |t| { join(t); }
    }
}

fn main(argv: ~[~str]) {
    if vec::len(argv) < 2u && !os::getenv(~"RUST_BENCH").is_some() {
        let out = io::stdout();

        out.write_line(fmt!("Usage: %s <filename> ...", argv[0]));

        return;
    }

    let readers: ~[fn~() -> word_reader]  = if argv.len() >= 2 {
        vec::view(argv, 1u, argv.len()).map(
            |f| fn~() -> word_reader { file_word_reader(f) } )
    }
    else {
        let num_readers = 50;
        let words_per_reader = 600;
        vec::from_fn(
            num_readers,
            |_i| fn~() -> word_reader {
                random_word_reader(words_per_reader) as word_reader
            })
    };

    let start = time::precise_time_ns();

    map_reduce::map_reduce(map, reduce, readers);
    let stop = time::precise_time_ns();

    let elapsed = (stop - start) / 1000000u64;

    log(error, ~"MapReduce completed in "
             + u64::str(elapsed) + ~"ms");
}

fn read_word(r: io::Reader) -> Option<~str> {
    let mut w = ~"";

    while !r.eof() {
        let c = r.read_char();

        if is_word_char(c) {
            w += str::from_char(c);
        } else { if w != ~"" { return Some(w); } }
    }
    return None;
}

fn is_word_char(c: char) -> bool {
    char::is_alphabetic(c) || char::is_digit(c) || c == '_'
}

struct random_word_reader: word_reader {
    mut remaining: uint,
    rng: rand::Rng,

    fn read_word() -> Option<~str> {
        if self.remaining > 0 {
            self.remaining -= 1;
            let len = self.rng.gen_uint_range(1, 4);
            Some(self.rng.gen_str(len))
        }
        else { None }
    }
}

fn random_word_reader(count: uint) -> random_word_reader {
    random_word_reader {
        remaining: count,
        rng: rand::Rng()
    }
}
<commit_msg>(fix incoming) Add the necessary traits to some generic functions<commit_after>/**
   A parallel word-frequency counting program.

   This is meant primarily to demonstrate Rust's MapReduce framework.

   It takes a list of files on the command line and outputs a list of
   words along with how many times each word is used.

*/

// xfail-pretty

use std;

use option = option;
use option::Some;
use option::None;
use std::map;
use std::map::hashmap;
use hash::Hash;
use io::WriterUtil;

use std::time;

use comm::Chan;
use comm::Port;
use comm::recv;
use comm::send;
use cmp::Eq;
use to_bytes::IterBytes;

macro_rules! move_out (
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
)

trait word_reader {
    fn read_word() -> Option<~str>;
}

trait hash_key {
    pure fn hash() -> uint;
    pure fn eq(&&k: self) -> bool;
}

impl ~str: hash_key {
    pure fn hash() -> uint { str::hash(&self) }
    pure fn eq(&&x: ~str) -> bool { self == x }
}

// These used to be in task, but they disappeard.
type joinable_task = Port<()>;
fn spawn_joinable(+f: fn~()) -> joinable_task {
    let p = Port();
    let c = Chan(p);
    do task::spawn() |move f| {
        f();
        c.send(());
    }
    p
}

fn join(t: joinable_task) {
    t.recv()
}

impl io::Reader: word_reader {
    fn read_word() -> Option<~str> { read_word(self) }
}

fn file_word_reader(filename: ~str) -> word_reader {
    match io::file_reader(&Path(filename)) {
      result::Ok(f) => { f as word_reader }
      result::Err(e) => { fail fmt!("%?", e) }
    }
}

fn map(f: fn~() -> word_reader, emit: map_reduce::putter<~str, int>) {
    let f = f();
    loop {
        match f.read_word() {
          Some(w) => { emit(w, 1); }
          None => { break; }
        }
    }
}

fn reduce(&&word: ~str, get: map_reduce::getter<int>) {
    let mut count = 0;

    loop { match get() { Some(_) => { count += 1; } None => { break; } } }

    io::println(fmt!("%s\t%?", word, count));
}

struct box<T> {
    mut contents: Option<T>,

    fn swap(f: fn(+T) -> T) {
        let mut tmp = None;
        self.contents <-> tmp;
        self.contents = Some(f(option::unwrap(tmp)));
    }

    fn unwrap() -> T {
        let mut tmp = None;
        self.contents <-> tmp;
        option::unwrap(tmp)
    }
}

fn box<T>(+x: T) -> box<T> {
    box {
        contents: Some(x)
    }
}

mod map_reduce {
    export putter;
    export getter;
    export mapper;
    export reducer;
    export map_reduce;

    type putter<K: Send, V: Send> = fn(K, V);

    type mapper<K1: Send, K2: Send, V: Send> = fn~(K1, putter<K2, V>);

    type getter<V: Send> = fn() -> Option<V>;

    type reducer<K: Copy Send, V: Copy Send> = fn~(K, getter<V>);

    enum ctrl_proto<K: Copy Send, V: Copy Send> {
        find_reducer(K, Chan<Chan<reduce_proto<V>>>),
        mapper_done
    }

    proto! ctrl_proto (
        open: send<K: Copy Send, V: Copy Send> {
            find_reducer(K) -> reducer_response<K, V>,
            mapper_done -> !
        }

        reducer_response: recv<K: Copy Send, V: Copy Send> {
            reducer(Chan<reduce_proto<V>>) -> open<K, V>
        }
    )

    enum reduce_proto<V: Copy Send> { emit_val(V), done, addref, release }

    fn start_mappers<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send hash_key,
                     V: Copy Send>(
        map: mapper<K1, K2, V>,
        &ctrls: ~[ctrl_proto::server::open<K2, V>],
        inputs: ~[K1])
        -> ~[joinable_task]
    {
        let mut tasks = ~[];
        for inputs.each |i| {
            let (ctrl, ctrl_server) = ctrl_proto::init();
            let ctrl = box(ctrl);
            vec::push(tasks, spawn_joinable(|| map_task(map, ctrl, i) ));
            vec::push(ctrls, ctrl_server);
        }
        return tasks;
    }

    fn map_task<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send hash_key, V: Copy Send>(
        map: mapper<K1, K2, V>,
        ctrl: box<ctrl_proto::client::open<K2, V>>,
        input: K1)
    {
        // log(error, "map_task " + input);
        let intermediates = map::hashmap();

        do map(input) |key, val| {
            let mut c = None;
            let found = intermediates.find(key);
            match found {
              Some(_c) => { c = Some(_c); }
              None => {
                do ctrl.swap |ctrl| {
                    let ctrl = ctrl_proto::client::find_reducer(ctrl, key);
                    match pipes::recv(ctrl) {
                      ctrl_proto::reducer(c_, ctrl) => {
                        c = Some(c_);
                        move_out!(ctrl)
                      }
                    }
                }
                intermediates.insert(key, c.get());
                send(c.get(), addref);
              }
            }
            send(c.get(), emit_val(val));
        }

        fn finish<K: Copy Send, V: Copy Send>(_k: K, v: Chan<reduce_proto<V>>)
        {
            send(v, release);
        }
        for intermediates.each_value |v| { send(v, release) }
        ctrl_proto::client::mapper_done(ctrl.unwrap());
    }

    fn reduce_task<K: Copy Send, V: Copy Send>(
        reduce: reducer<K, V>,
        key: K,
        out: Chan<Chan<reduce_proto<V>>>)
    {
        let p = Port();

        send(out, Chan(p));

        let mut ref_count = 0;
        let mut is_done = false;

        fn get<V: Copy Send>(p: Port<reduce_proto<V>>,
                             &ref_count: int, &is_done: bool)
           -> Option<V> {
            while !is_done || ref_count > 0 {
                match recv(p) {
                  emit_val(v) => {
                    // error!("received %d", v);
                    return Some(v);
                  }
                  done => {
                    // error!("all done");
                    is_done = true;
                  }
                  addref => { ref_count += 1; }
                  release => { ref_count -= 1; }
                }
            }
            return None;
        }

        reduce(key, || get(p, ref_count, is_done) );
    }

    fn map_reduce<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send hash_key, V: Copy Send>(
        map: mapper<K1, K2, V>,
        reduce: reducer<K2, V>,
        inputs: ~[K1])
    {
        let mut ctrl = ~[];

        // This task becomes the master control task. It task::_spawns
        // to do the rest.

        let reducers = map::hashmap();
        let mut tasks = start_mappers(map, ctrl, inputs);
        let mut num_mappers = vec::len(inputs) as int;

        while num_mappers > 0 {
            let (_ready, message, ctrls) = pipes::select(ctrl);
            match option::unwrap(message) {
              ctrl_proto::mapper_done => {
                // error!("received mapper terminated.");
                num_mappers -= 1;
                ctrl = ctrls;
              }
              ctrl_proto::find_reducer(k, cc) => {
                let c;
                // log(error, "finding reducer for " + k);
                match reducers.find(k) {
                  Some(_c) => {
                    // log(error,
                    // "reusing existing reducer for " + k);
                    c = _c;
                  }
                  None => {
                    // log(error, "creating new reducer for " + k);
                    let p = Port();
                    let ch = Chan(p);
                    let r = reduce, kk = k;
                    vec::push(tasks,
                              spawn_joinable(|| reduce_task(r, kk, ch) ));
                    c = recv(p);
                    reducers.insert(k, c);
                  }
                }
                ctrl = vec::append_one(
                    ctrls,
                    ctrl_proto::server::reducer(move_out!(cc), c));
              }
            }
        }

        for reducers.each_value |v| { send(v, done) }

        for tasks.each |t| { join(t); }
    }
}

fn main(argv: ~[~str]) {
    if vec::len(argv) < 2u && !os::getenv(~"RUST_BENCH").is_some() {
        let out = io::stdout();

        out.write_line(fmt!("Usage: %s <filename> ...", argv[0]));

        return;
    }

    let readers: ~[fn~() -> word_reader]  = if argv.len() >= 2 {
        vec::view(argv, 1u, argv.len()).map(
            |f| fn~() -> word_reader { file_word_reader(f) } )
    }
    else {
        let num_readers = 50;
        let words_per_reader = 600;
        vec::from_fn(
            num_readers,
            |_i| fn~() -> word_reader {
                random_word_reader(words_per_reader) as word_reader
            })
    };

    let start = time::precise_time_ns();

    map_reduce::map_reduce(map, reduce, readers);
    let stop = time::precise_time_ns();

    let elapsed = (stop - start) / 1000000u64;

    log(error, ~"MapReduce completed in "
             + u64::str(elapsed) + ~"ms");
}

fn read_word(r: io::Reader) -> Option<~str> {
    let mut w = ~"";

    while !r.eof() {
        let c = r.read_char();

        if is_word_char(c) {
            w += str::from_char(c);
        } else { if w != ~"" { return Some(w); } }
    }
    return None;
}

fn is_word_char(c: char) -> bool {
    char::is_alphabetic(c) || char::is_digit(c) || c == '_'
}

struct random_word_reader: word_reader {
    mut remaining: uint,
    rng: rand::Rng,

    fn read_word() -> Option<~str> {
        if self.remaining > 0 {
            self.remaining -= 1;
            let len = self.rng.gen_uint_range(1, 4);
            Some(self.rng.gen_str(len))
        }
        else { None }
    }
}

fn random_word_reader(count: uint) -> random_word_reader {
    random_word_reader {
        remaining: count,
        rng: rand::Rng()
    }
}
<|endoftext|>


<commit_before>use {ffi, Raii, Return, Handle, Statement, Result, Prepared, Allocated, NoResult, ResultSetState};

impl<'a, 'b> Statement<'a, 'b, Allocated, NoResult> {
    /// Prepares a statement for execution. Executing a prepared statement is faster than directly
    /// executing an unprepared statement, since it is already compiled into an Access Plan. This
    /// makes preparing statement a good idea if you want to repeatedly execute a query with a
    /// different set of parameters and care about performance.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use odbc::*;
    /// # fn doc() -> Result<()>{
    /// let env = Environment::new().unwrap().set_odbc_version_3()?;
    /// let conn = DataSource::with_parent(&env)?.connect("TestDataSource", "", "")?;
    /// let stmt = Statement::with_parent(&conn)?;
    /// let mut stmt = stmt.prepare("SELECT TITLE FROM MOVIES WHERE YEAR = ?")?;
    ///
    /// fn print_one_movie_from<'a> (year: u16, stmt: Statement<'a,'a, Prepared, NoResult>) -> Result<Statement<'a, 'a, Prepared, NoResult>>{
    ///    let stmt = stmt.bind_parameter(1, &year)?;
    ///    let stmt = if let Data(mut stmt) = stmt.execute()?{
    ///        if let Some(mut cursor) = stmt.fetch()?{
    ///            println!("{}", cursor.get_data::<String>(1)?.unwrap());
    ///        }
    ///        stmt.close_cursor()?
    ///    } else {
    ///       panic!("SELECT statement returned no result set");
    ///    };
    ///    stmt.reset_parameters()
    /// };
    ///
    /// for year in 1990..2010{
    ///     stmt = print_one_movie_from(year, stmt)?
    /// }
    ///
    /// # Ok(())
    /// # }
    /// ```
    pub fn prepare(mut self, sql_text: &str) -> Result<Statement<'a, 'b, Prepared, NoResult>> {
        self.raii.prepare(sql_text).into_result(&mut self)?;
        Ok(Statement::with_raii(self.raii))
    }
}

impl<'a, 'b> Statement<'a, 'b, Prepared, NoResult> {
    /// Executes a prepared statement.
    pub fn execute(mut self) -> Result<ResultSetState<'a, 'b, Prepared>> {
        if self.raii.execute().into_result(&mut self)? {
            Ok(ResultSetState::Data(Statement::with_raii(self.raii)))
        } else {
            Ok(ResultSetState::NoData(Statement::with_raii(self.raii)))
        }
    }
}

impl Raii<ffi::Stmt> {
    fn prepare(&mut self, sql_text: &str) -> Return<()> {
        match unsafe {
            ffi::SQLPrepare(self.handle(),
                            sql_text.as_bytes().as_ptr(),
                            sql_text.as_bytes().len() as ffi::SQLINTEGER)
        } {
            ffi::SQL_SUCCESS => Return::Success(()),
            ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(()),
            ffi::SQL_ERROR => Return::Error,
            r => panic!("SQLPrepare returned unexpected result: {:?}", r),
        }
    }

    fn execute(&mut self) -> Return<bool> {
        match unsafe { ffi::SQLExecute(self.handle()) } {
            ffi::SQL_SUCCESS => Return::Success(true),
            ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(true),
            ffi::SQL_ERROR => Return::Error,
            ffi::SQL_NO_DATA => Return::Success(false),
            r => panic!("SQLExecute returned unexpected result: {:?}", r),
        }
    }
}
<commit_msg>allow describing the columns of a prepared statement<commit_after>use {ffi, ColumnDescriptor, Raii, Return, Handle, Statement, Result, Prepared, Allocated,
     NoResult, ResultSetState};

impl<'a, 'b> Statement<'a, 'b, Allocated, NoResult> {
    /// Prepares a statement for execution. Executing a prepared statement is faster than directly
    /// executing an unprepared statement, since it is already compiled into an Access Plan. This
    /// makes preparing statement a good idea if you want to repeatedly execute a query with a
    /// different set of parameters and care about performance.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use odbc::*;
    /// # fn doc() -> Result<()>{
    /// let env = Environment::new().unwrap().set_odbc_version_3()?;
    /// let conn = DataSource::with_parent(&env)?.connect("TestDataSource", "", "")?;
    /// let stmt = Statement::with_parent(&conn)?;
    /// let mut stmt = stmt.prepare("SELECT TITLE FROM MOVIES WHERE YEAR = ?")?;
    ///
    /// fn print_one_movie_from<'a> (year: u16, stmt: Statement<'a,'a, Prepared, NoResult>) -> Result<Statement<'a, 'a, Prepared, NoResult>>{
    ///    let stmt = stmt.bind_parameter(1, &year)?;
    ///    let stmt = if let Data(mut stmt) = stmt.execute()?{
    ///        if let Some(mut cursor) = stmt.fetch()?{
    ///            println!("{}", cursor.get_data::<String>(1)?.unwrap());
    ///        }
    ///        stmt.close_cursor()?
    ///    } else {
    ///       panic!("SELECT statement returned no result set");
    ///    };
    ///    stmt.reset_parameters()
    /// };
    ///
    /// for year in 1990..2010{
    ///     stmt = print_one_movie_from(year, stmt)?
    /// }
    ///
    /// # Ok(())
    /// # }
    /// ```
    pub fn prepare(mut self, sql_text: &str) -> Result<Statement<'a, 'b, Prepared, NoResult>> {
        self.raii.prepare(sql_text).into_result(&mut self)?;
        Ok(Statement::with_raii(self.raii))
    }
}

impl<'a, 'b> Statement<'a, 'b, Prepared, NoResult> {
    /// The number of columns in a result set
    ///
    /// Can be called successfully only when the statement is in the prepared, executed, or
    /// positioned state. If the statement does not return columns the result will be 0.
    pub fn num_result_cols(&self) -> Result<i16> {
        self.raii.num_result_cols().into_result(self)
    }

    /// Returns description struct for result set column with a given index. Note: indexing is starting from 1.
    pub fn describe_col(&self, idx: u16) -> Result<ColumnDescriptor> {
        self.raii.describe_col(idx).into_result(self)
    }

    /// Executes a prepared statement.
    pub fn execute(mut self) -> Result<ResultSetState<'a, 'b, Prepared>> {
        if self.raii.execute().into_result(&mut self)? {
            Ok(ResultSetState::Data(Statement::with_raii(self.raii)))
        } else {
            Ok(ResultSetState::NoData(Statement::with_raii(self.raii)))
        }
    }
}

impl Raii<ffi::Stmt> {
    fn prepare(&mut self, sql_text: &str) -> Return<()> {
        match unsafe {
                  ffi::SQLPrepare(self.handle(),
                                  sql_text.as_bytes().as_ptr(),
                                  sql_text.as_bytes().len() as ffi::SQLINTEGER)
              } {
            ffi::SQL_SUCCESS => Return::Success(()),
            ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(()),
            ffi::SQL_ERROR => Return::Error,
            r => panic!("SQLPrepare returned unexpected result: {:?}", r),
        }
    }

    fn execute(&mut self) -> Return<bool> {
        match unsafe { ffi::SQLExecute(self.handle()) } {
            ffi::SQL_SUCCESS => Return::Success(true),
            ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(true),
            ffi::SQL_ERROR => Return::Error,
            ffi::SQL_NO_DATA => Return::Success(false),
            r => panic!("SQLExecute returned unexpected result: {:?}", r),
        }
    }
}
<|endoftext|>


<commit_before>//! A library to read binary protobuf files
//!
//! This reader is developed similarly to a pull reader

#![deny(missing_docs)]
#![allow(dead_code)]

extern crate byteorder;
extern crate failure;
#[macro_use]
extern crate failure_derive;

pub mod errors;
pub mod message;
pub mod reader;
pub mod sizeofs;
pub mod writer;

pub use errors::{Error, Result};
pub use message::{MessageRead, MessageWrite};
pub use reader::{deserialize_from_slice, BytesReader, Reader};
pub use writer::{serialize_into_vec, Writer};
<commit_msg>Removed #[macro_use] to clear warning.<commit_after>//! A library to read binary protobuf files
//!
//! This reader is developed similarly to a pull reader

#![deny(missing_docs)]
#![allow(dead_code)]

extern crate byteorder;
extern crate failure;
extern crate failure_derive;

pub mod errors;
pub mod message;
pub mod reader;
pub mod sizeofs;
pub mod writer;

pub use errors::{Error, Result};
pub use message::{MessageRead, MessageWrite};
pub use reader::{deserialize_from_slice, BytesReader, Reader};
pub use writer::{serialize_into_vec, Writer};
<|endoftext|>