<commit_before>use crate::schema::SCHEMA;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::{
    collections::{HashMap, VecDeque},
    convert::TryInto,
};
use wasm_bindgen::JsCast;
use yew::{
    html,
    prelude::*,
    services::{storage::Area, StorageService},
    web_sys::HtmlElement,
};

pub type Ref = String;

pub const INVALID_REF: &str = "-";

pub fn new_ref() -> Ref {
    uuid::Uuid::new_v4().to_hyphenated().to_string()
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Selector {
    pub field: String,
    pub index: usize,
}

pub type Path = VecDeque<Selector>;

pub fn append(path: &Path, selector: Selector) -> Path {
    let mut new_path = path.clone();
    new_path.push_back(selector);
    new_path
}

pub struct Model {
    pub file: File,
    pub store: StorageService,
    pub cursor: Path,

    pub link: ComponentLink<Self>,

    pub raw_command: String,
    pub parsed_commands: Vec<Node>,
    pub selected_command_index: usize,
}

impl Model {
    pub fn lookup(&self, reference: &Ref) -> Option<&Node> {
        self.file.lookup(reference)
    }
    pub fn lookup_mut(&mut self, reference: &Ref) -> Option<&mut Node> {
        self.file.lookup_mut(reference)
    }
    pub fn lookup_path(&self, reference: &Ref, relative_path: Path) -> Option<Ref> {
        let mut path = relative_path;
        match path.pop_front() {
            Some(head) => {
                let base = self.lookup(reference).unwrap();
                let children = &base.children.get(&head.field).cloned().unwrap_or_default();
                let r = children.get(head.index).cloned().unwrap_or_default();
                self.lookup_path(&r, path)
            }
            None => Some(reference.clone()),
        }
    }

    pub fn parent_ref(&self) -> Option<Ref> {
        let mut parent_cursor = self.cursor.clone();
        parent_cursor.pop_back().unwrap();
        self.lookup_path(&self.file.root, parent_cursor)
    }

    pub fn current_ref(&self) -> Option<Ref> {
        self.lookup_path(&self.file.root, self.cursor.clone())
    }

    fn parse_commands(&mut self) -> Vec<Node> {
        self.current_field()
            .map(|field| {
                field
                    .kind
                    .iter()
                    .filter_map(|kind| SCHEMA.get_kind(kind))
                    .filter_map(|kind| {
                        (kind.parser)(&self.raw_command).map(|value| Node {
                            kind: kind.name.to_string(),
                            value,
                            children: HashMap::new(),
                        })
                    })
                    .collect::<Vec<_>>()
            })
            .unwrap_or_default()
        // let mut value = match command {
        //     "false" => Some(Value::Bool(false)),
        //     "true" => Some(Value::Bool(true)),
        //     _ => {
        //         if let Some(v) = command.strip_prefix('"') {
        //             Some(Value::String(v.to_string()))
        //         } else if let Ok(v) = command.parse::<i32>() {
        //             Some(Value::Int(v))
        //         } else if let Some(_) = SCHEMA.kinds.iter().find(|k| k.name == command) {
        //             Some(Value::Inner(Inner {
        //                 kind: command.to_string(),
        //                 children: HashMap::new(),
        //             }))
        //         } else {
        //             None
        //         }
        //     }
        // };
        // if let Some(Value::Inner(ref mut inner)) = value {
        //     let kind = SCHEMA.kinds.iter().find(|k| k.name == inner.kind).unwrap();
        //     if let Some(inner_field) = kind.inner {
        //         if let Some(reference) = self.current_ref() {
        //             inner
        //                 .children
        //                 .entry(inner_field.to_string())
        //                 .or_default()
        //                 .push(reference);
        //         }
        //     }
        // }
        // if let Some(v) = &value {
        //     let valid = self.is_valid_value(v);
        //     log::info!("valid: {:?}", valid);
        // }
        // value
    }

    fn prev(&mut self) {
        let flattened_paths = self.flatten_paths(&self.file.root, Path::new());
        log::info!("paths: {:?}", flattened_paths);
        let current_path_index = flattened_paths.iter().position(|x| *x == self.cursor);
        log::info!("current: {:?}", current_path_index);
        if let Some(current_path_index) = current_path_index {
            if current_path_index > 0 {
                if let Some(path) = flattened_paths.get(current_path_index - 1) {
                    self.cursor = path.clone();
                }
            }
        }
    }

    fn next(&mut self) {
        let flattened_paths = self.flatten_paths(&self.file.root, Path::new());
        log::info!("paths: {:?}", flattened_paths);
        let current_path_index = flattened_paths.iter().position(|x| *x == self.cursor);
        log::info!("current: {:?}", current_path_index);
        if let Some(current_path_index) = current_path_index {
            if let Some(path) = flattened_paths.get(current_path_index + 1) {
                self.cursor = path.clone();
            }
        } else {
            if let Some(path) = flattened_paths.get(0) {
                self.cursor = path.clone();
            }
        }
    }

    fn set_value(&mut self, node: Node) {
        let new_ref = self.file.add_node(node);

        let selector = self.cursor.back().unwrap().clone();
        let parent_ref = self.parent_ref().unwrap();
        log::info!("parent ref: {:?}", parent_ref);
        let parent = self.lookup_mut(&parent_ref).unwrap();
        log::info!("parent: {:?}", parent);

        // If the field does not exist, create a default one.
        let children = parent.children.entry(selector.field).or_default();
        match children.get_mut(selector.index) {
            Some(c) => *c = new_ref,
            None => children.push(new_ref),
        }
    }

    pub fn focus_command_line(&self) {
        yew::utils::document()
            .query_selector("#command-line")
            .unwrap()
            .unwrap()
            .dyn_into::<HtmlElement>()
            .unwrap()
            .focus()
            .unwrap();
    }
}

#[derive(Clone)]
pub enum Msg {
    Noop,

    Select(Path),

    Store,
    Load,

    Prev,
    Next,
    Parent,

    AddItem,
    DeleteItem,

    SetCommand(String),
    ReplaceCurrentNode(Node),
    CommandKey(KeyboardEvent),
}

#[derive(Serialize, Deserialize)]
pub struct File {
    pub nodes: HashMap<Ref, Node>,
    pub root: Ref,
}

impl File {
    pub fn lookup(&self, reference: &Ref) -> Option<&Node> {
        self.nodes.get(reference)
    }

    fn lookup_mut(&mut self, reference: &Ref) -> Option<&mut Node> {
        self.nodes.get_mut(reference)
    }

    fn add_node(&mut self, node: Node) -> Ref {
        let reference = new_ref();
        self.nodes.insert(reference.clone(), node);
        reference
    }
}

// TODO: Navigate to children directly, but use :var to navigate to variables, otherwise skip them
// when navigating.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Node {
    pub kind: String,
    pub value: String,
    pub children: HashMap<String, Vec<Ref>>,
}

fn display_selector(selector: &Selector) -> Vec {
    let mut segments = Vec::new();
    segments.push(html! {

          { selector.field.clone() }
              { format!("[{}]", selector.index) }

    });
    segments.push(html! {

          { format!("[{}]", selector.index) }

    });
    segments
}

fn display_cursor(cursor: &Path) -> Html {
    let segments = cursor
        .iter()
        .flat_map(|s| display_selector(s))
        .intersperse(html! { { ">" }});
    html! {

{ for segments }

    }
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn view(&self) -> Html {
        let onkeypress = self
            .link
            .callback(move |e: KeyboardEvent| Msg::CommandKey(e));
        let oninput = self
            .link
            .callback(move |e: InputData| Msg::SetCommand(e.value));
        let onblur = self.link.callback(move |e: FocusEvent| Msg::Noop);
        let values = self.parsed_commands.iter().enumerate().map(|(i, v)| {
            let s = v.clone();
            // let callback = self.link.callback(move |_| Msg::ReplaceCurrentNode(v));
            let mut classes = vec!["border", "border-solid", "border-blue-500"];
            if self.selected_command_index == i {
                classes.push("bg-yellow-500");
            }
            html! {

{ v.kind.clone() }

            }
        });
        html! {

{ "LINC" }

{ self.view_actions() }

                    // <CommandLine values=allowed_kinds on_change=callback base_value=self.command.clone() state=state />

                        <input
                          id="command-line"
                          class="w-full border border-solid border-blue-500 bg-blue-100 font-mono"
                          oninput=oninput
                          onblur=onblur
                          value=self.raw_command
                        />
                        { for values }

{ self.view_file(&self.file) }

{ display_cursor(&self.cursor) }

{ format!("Ref: {:?}", self.lookup_path(&self.file.root, self.cursor.clone())) }

{ self.view_file_json(&self.file) }

        }
    }

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        Model {
            store: StorageService::new(Area::Local).expect("could not create storage service"),
            raw_command: "".to_string(),
            parsed_commands: vec![],
            selected_command_index: 0,
            file: super::initial::initial(),
            cursor: VecDeque::new(),
            link,
        }
    }

    fn change(&mut self, _props: ()) -> ShouldRender {
        false
    }

    fn rendered(&mut self, _first_render: bool) {
        self.focus_command_line();
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        const KEY: &str = "linc_file";
        match msg {
            Msg::Noop => {}
            Msg::Select(path) => {
                self.cursor = path;
                self.parsed_commands = self.parse_commands();
            }
            // TODO: sibling vs inner
            Msg::Prev => {
                self.prev();
                self.parsed_commands = self.parse_commands();
            }
            // Preorder tree traversal.
            Msg::Next => {
                self.next();
                self.parsed_commands = self.parse_commands();
            }
            Msg::Parent => {
                self.cursor.pop_back();
                self.parsed_commands = self.parse_commands();
            }
            Msg::Store => {
                self.store.store(KEY, yew::format::Json(&self.file));
            }
            Msg::Load => {
                if let yew::format::Json(Ok(file)) = self.store.restore(KEY) {
                    self.file = file;
                }
            }
            Msg::ReplaceCurrentNode(n) => {
                self.file.nodes.insert(self.current_ref().unwrap(), n);
                self.parsed_commands = self.parse_commands();
                self.selected_command_index = 0;
            }
            Msg::AddItem => {
                let selector = self.cursor.back().unwrap().clone();
                let parent_ref = self.parent_ref().unwrap();
                let new_ref = self.file.add_node(Node {
                    kind: "invalid".to_string(),
                    value: "invalid".to_string(),
                    children: HashMap::new(),
                });
                let parent = self.lookup_mut(&parent_ref).unwrap();
                log::info!("inner");
                // If the field does not exist, create a default one.
                let children = parent.children.entry(selector.field).or_default();
                let new_index = selector.index + 1;
                children.insert(new_index, new_ref);
                // Select newly created element.
                self.cursor.back_mut().unwrap().index = new_index;
            }
            Msg::DeleteItem => {
                let selector = self.cursor.back().unwrap().clone();
                let parent_ref = self.parent_ref().unwrap();
                let parent = self.lookup_mut(&parent_ref).unwrap();
                // If the field does not exist, create a default one.
                let children = parent.children.entry(selector.field).or_default();
                children.remove(selector.index);
            }
            Msg::SetCommand(v) => {
                self.raw_command = v;
                self.parsed_commands = self.parse_commands();
                self.selected_command_index = 0;
            }
            Msg::CommandKey(v) => {
                log::info!("key: {}", v.key());
                // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
                match v.key().as_ref() {
                    "Enter" => match self
                        .parsed_commands
                        .get(self.selected_command_index)
                        .clone()
                    {
                        Some(node) => {
                            // Replace current node.
                            // self.file
                            //     .nodes
                            //     .insert(self.current_ref().unwrap(), node.clone());
                            self.set_value(node.clone());
                            self.next();
                            self.raw_command = "".to_string();
                            self.parsed_commands = self.parse_commands();
                            self.selected_command_index = 0;
                        }
                        None => log::info!("invalid command"),
                    },
                    "Escape" => {
                        self.raw_command = "".to_string();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    "ArrowUp" => {
                        if self.selected_command_index > 0 {
                            self.selected_command_index -= 1;
                        }
                    }
                    "ArrowDown" => {
                        if self.selected_command_index < (self.parsed_commands.len() - 1) {
                            self.selected_command_index += 1;
                        }
                    }
                    "ArrowRight" if self.raw_command.is_empty() => {
                        self.next();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    "ArrowLeft" if self.raw_command.is_empty() => {
                        self.prev();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    _ => {}
                }
            }
        };
        self.focus_command_line();
        true
    }
}

pub struct Action {
    pub text: String,
    pub msg: Msg,
}
<commit_msg>guide<commit_after>use crate::schema::SCHEMA;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::{
    collections::{HashMap, VecDeque},
    convert::TryInto,
};
use wasm_bindgen::JsCast;
use yew::{
    html,
    prelude::*,
    services::{storage::Area, StorageService},
    web_sys::HtmlElement,
};

pub type Ref = String;

pub const INVALID_REF: &str = "-";

pub fn new_ref() -> Ref {
    uuid::Uuid::new_v4().to_hyphenated().to_string()
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Selector {
    pub field: String,
    pub index: usize,
}

pub type Path = VecDeque<Selector>;

pub fn append(path: &Path, selector: Selector) -> Path {
    let mut new_path = path.clone();
    new_path.push_back(selector);
    new_path
}

pub struct Model {
    pub file: File,
    pub store: StorageService,
    pub cursor: Path,

    pub link: ComponentLink<Self>,

    pub raw_command: String,
    pub parsed_commands: Vec<Node>,
    pub selected_command_index: usize,
}

impl Model {
    pub fn lookup(&self, reference: &Ref) -> Option<&Node> {
        self.file.lookup(reference)
    }
    pub fn lookup_mut(&mut self, reference: &Ref) -> Option<&mut Node> {
        self.file.lookup_mut(reference)
    }
    pub fn lookup_path(&self, reference: &Ref, relative_path: Path) -> Option<Ref> {
        let mut path = relative_path;
        match path.pop_front() {
            Some(head) => {
                let base = self.lookup(reference).unwrap();
                let children = &base.children.get(&head.field).cloned().unwrap_or_default();
                let r = children.get(head.index).cloned().unwrap_or_default();
                self.lookup_path(&r, path)
            }
            None => Some(reference.clone()),
        }
    }

    pub fn parent_ref(&self) -> Option<Ref> {
        let mut parent_cursor = self.cursor.clone();
        parent_cursor.pop_back().unwrap();
        self.lookup_path(&self.file.root, parent_cursor)
    }

    pub fn current_ref(&self) -> Option<Ref> {
        self.lookup_path(&self.file.root, self.cursor.clone())
    }

    fn parse_commands(&mut self) -> Vec<Node> {
        self.current_field()
            .map(|field| {
                field
                    .kind
                    .iter()
                    .filter_map(|kind| SCHEMA.get_kind(kind))
                    .filter_map(|kind| {
                        (kind.parser)(&self.raw_command).map(|value| Node {
                            kind: kind.name.to_string(),
                            value,
                            children: HashMap::new(),
                        })
                    })
                    .collect::<Vec<_>>()
            })
            .unwrap_or_default()
        // let mut value = match command {
        //     "false" => Some(Value::Bool(false)),
        //     "true" => Some(Value::Bool(true)),
        //     _ => {
        //         if let Some(v) = command.strip_prefix('"') {
        //             Some(Value::String(v.to_string()))
        //         } else if let Ok(v) = command.parse::<i32>() {
        //             Some(Value::Int(v))
        //         } else if let Some(_) = SCHEMA.kinds.iter().find(|k| k.name == command) {
        //             Some(Value::Inner(Inner {
        //                 kind: command.to_string(),
        //                 children: HashMap::new(),
        //             }))
        //         } else {
        //             None
        //         }
        //     }
        // };
        // if let Some(Value::Inner(ref mut inner)) = value {
        //     let kind = SCHEMA.kinds.iter().find(|k| k.name == inner.kind).unwrap();
        //     if let Some(inner_field) = kind.inner {
        //         if let Some(reference) = self.current_ref() {
        //             inner
        //                 .children
        //                 .entry(inner_field.to_string())
        //                 .or_default()
        //                 .push(reference);
        //         }
        //     }
        // }
        // if let Some(v) = &value {
        //     let valid = self.is_valid_value(v);
        //     log::info!("valid: {:?}", valid);
        // }
        // value
    }

    fn prev(&mut self) {
        let flattened_paths = self.flatten_paths(&self.file.root, Path::new());
        log::info!("paths: {:?}", flattened_paths);
        let current_path_index = flattened_paths.iter().position(|x| *x == self.cursor);
        log::info!("current: {:?}", current_path_index);
        if let Some(current_path_index) = current_path_index {
            if current_path_index > 0 {
                if let Some(path) = flattened_paths.get(current_path_index - 1) {
                    self.cursor = path.clone();
                }
            }
        }
    }

    fn next(&mut self) {
        let flattened_paths = self.flatten_paths(&self.file.root, Path::new());
        log::info!("paths: {:?}", flattened_paths);
        let current_path_index = flattened_paths.iter().position(|x| *x == self.cursor);
        log::info!("current: {:?}", current_path_index);
        if let Some(current_path_index) = current_path_index {
            if let Some(path) = flattened_paths.get(current_path_index + 1) {
                self.cursor = path.clone();
            }
        } else {
            if let Some(path) = flattened_paths.get(0) {
                self.cursor = path.clone();
            }
        }
    }

    fn set_value(&mut self, node: Node) {
        let new_ref = self.file.add_node(node);

        let selector = self.cursor.back().unwrap().clone();
        let parent_ref = self.parent_ref().unwrap();
        log::info!("parent ref: {:?}", parent_ref);
        let parent = self.lookup_mut(&parent_ref).unwrap();
        log::info!("parent: {:?}", parent);

        // If the field does not exist, create a default one.
        let children = parent.children.entry(selector.field).or_default();
        match children.get_mut(selector.index) {
            Some(c) => *c = new_ref,
            None => children.push(new_ref),
        }
    }

    pub fn focus_command_line(&self) {
        yew::utils::document()
            .query_selector("#command-line")
            .unwrap()
            .unwrap()
            .dyn_into::<HtmlElement>()
            .unwrap()
            .focus()
            .unwrap();
    }
}

#[derive(Clone)]
pub enum Msg {
    Noop,

    Select(Path),

    Store,
    Load,

    Prev,
    Next,
    Parent,

    AddItem,
    DeleteItem,

    SetCommand(String),
    ReplaceCurrentNode(Node),
    CommandKey(KeyboardEvent),
}

#[derive(Serialize, Deserialize)]
pub struct File {
    pub nodes: HashMap<Ref, Node>,
    pub root: Ref,
}

impl File {
    pub fn lookup(&self, reference: &Ref) -> Option<&Node> {
        self.nodes.get(reference)
    }

    fn lookup_mut(&mut self, reference: &Ref) -> Option<&mut Node> {
        self.nodes.get_mut(reference)
    }

    fn add_node(&mut self, node: Node) -> Ref {
        let reference = new_ref();
        self.nodes.insert(reference.clone(), node);
        reference
    }
}

// TODO: Navigate to children directly, but use :var to navigate to variables, otherwise skip them
// when navigating.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Node {
    pub kind: String,
    pub value: String,
    pub children: HashMap<String, Vec<Ref>>,
}

fn display_selector(selector: &Selector) -> Vec {
    let mut segments = Vec::new();
    segments.push(html! {

          { selector.field.clone() }
              { format!("[{}]", selector.index) }

    });
    segments.push(html! {

          { format!("[{}]", selector.index) }

    });
    segments
}

fn display_cursor(cursor: &Path) -> Html {
    let segments = cursor
        .iter()
        .flat_map(|s| display_selector(s))
        .intersperse(html! { { ">" }});
    html! {

{ for segments }

    }
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn view(&self) -> Html {
        let onkeypress = self
            .link
            .callback(move |e: KeyboardEvent| Msg::CommandKey(e));
        let oninput = self
            .link
            .callback(move |e: InputData| Msg::SetCommand(e.value));
        let onblur = self.link.callback(move |e: FocusEvent| Msg::Noop);
        let values = self.parsed_commands.iter().enumerate().map(|(i, v)| {
            let s = v.clone();
            // let callback = self.link.callback(move |_| Msg::ReplaceCurrentNode(v));
            let mut classes = vec!["border", "border-solid", "border-blue-500"];
            if self.selected_command_index == i {
                classes.push("bg-yellow-500");
            }
            html! {

{ v.kind.clone() }

            }
        });
        html! {

{ "LINC" }

{ "left / right arrow keys (when command line is empty): move between existing nodes" }

{ "up / down arrow keys: select alternative completion result" }

{ "start typing in command line to filter available completion results" }

{ self.view_actions() }

                    // <CommandLine values=allowed_kinds on_change=callback base_value=self.command.clone() state=state />

                        <input
                          id="command-line"
                          class="w-full border border-solid border-blue-500 bg-blue-100 font-mono"
                          oninput=oninput
                          onblur=onblur
                          value=self.raw_command
                        />
                        { for values }

{ self.view_file(&self.file) }

{ display_cursor(&self.cursor) }

{ format!("Ref: {:?}", self.lookup_path(&self.file.root, self.cursor.clone())) }

{ self.view_file_json(&self.file) }

        }
    }

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        Model {
            store: StorageService::new(Area::Local).expect("could not create storage service"),
            raw_command: "".to_string(),
            parsed_commands: vec![],
            selected_command_index: 0,
            file: super::initial::initial(),
            cursor: vec![Selector {
                field: "items".to_string(),
                index: 0,
            }]
            .into(),
            link,
        }
    }

    fn change(&mut self, _props: ()) -> ShouldRender {
        self.focus_command_line();
        false
    }

    fn rendered(&mut self, _first_render: bool) {
        self.focus_command_line();
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        const KEY: &str = "linc_file";
        match msg {
            Msg::Noop => {}
            Msg::Select(path) => {
                self.cursor = path;
                self.parsed_commands = self.parse_commands();
            }
            // TODO: sibling vs inner
            Msg::Prev => {
                self.prev();
                self.parsed_commands = self.parse_commands();
            }
            // Preorder tree traversal.
            Msg::Next => {
                self.next();
                self.parsed_commands = self.parse_commands();
            }
            Msg::Parent => {
                self.cursor.pop_back();
                self.parsed_commands = self.parse_commands();
            }
            Msg::Store => {
                self.store.store(KEY, yew::format::Json(&self.file));
            }
            Msg::Load => {
                if let yew::format::Json(Ok(file)) = self.store.restore(KEY) {
                    self.file = file;
                }
            }
            Msg::ReplaceCurrentNode(n) => {
                self.file.nodes.insert(self.current_ref().unwrap(), n);
                self.parsed_commands = self.parse_commands();
                self.selected_command_index = 0;
            }
            Msg::AddItem => {
                let selector = self.cursor.back().unwrap().clone();
                let parent_ref = self.parent_ref().unwrap();
                let new_ref = self.file.add_node(Node {
                    kind: "invalid".to_string(),
                    value: "invalid".to_string(),
                    children: HashMap::new(),
                });
                let parent = self.lookup_mut(&parent_ref).unwrap();
                log::info!("inner");
                // If the field does not exist, create a default one.
                let children = parent.children.entry(selector.field).or_default();
                let new_index = selector.index + 1;
                children.insert(new_index, new_ref);
                // Select newly created element.
                self.cursor.back_mut().unwrap().index = new_index;
            }
            Msg::DeleteItem => {
                let selector = self.cursor.back().unwrap().clone();
                let parent_ref = self.parent_ref().unwrap();
                let parent = self.lookup_mut(&parent_ref).unwrap();
                // If the field does not exist, create a default one.
                let children = parent.children.entry(selector.field).or_default();
                children.remove(selector.index);
            }
            Msg::SetCommand(v) => {
                self.raw_command = v;
                self.parsed_commands = self.parse_commands();
                self.selected_command_index = 0;
            }
            Msg::CommandKey(v) => {
                log::info!("key: {}", v.key());
                // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
                match v.key().as_ref() {
                    "Enter" => match self
                        .parsed_commands
                        .get(self.selected_command_index)
                        .clone()
                    {
                        Some(node) => {
                            // Replace current node.
                            // self.file
                            //     .nodes
                            //     .insert(self.current_ref().unwrap(), node.clone());
                            self.set_value(node.clone());
                            self.next();
                            self.raw_command = "".to_string();
                            self.parsed_commands = self.parse_commands();
                            self.selected_command_index = 0;
                        }
                        None => log::info!("invalid command"),
                    },
                    "Escape" => {
                        self.raw_command = "".to_string();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    "ArrowUp" => {
                        if self.selected_command_index > 0 {
                            self.selected_command_index -= 1;
                        }
                    }
                    "ArrowDown" => {
                        if self.selected_command_index < (self.parsed_commands.len() - 1) {
                            self.selected_command_index += 1;
                        }
                    }
                    "ArrowRight" if self.raw_command.is_empty() => {
                        self.next();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    "ArrowLeft" if self.raw_command.is_empty() => {
                        self.prev();
                        self.parsed_commands = self.parse_commands();
                        self.selected_command_index = 0;
                    }
                    _ => {}
                }
            }
        };
        self.focus_command_line();
        true
    }
}

pub struct Action {
    pub text: String,
    pub msg: Msg,
}
<|endoftext|>


<commit_before>use std::error;
use std::ffi::CStr;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::str::Utf8Error;

use libc;
use ffi;

use error::Error;

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

macro_rules! list_iterator {
    ($item:ty, $constructor:path) => {
        type Item = $item;

        fn next(&mut self) -> Option<Self::Item> {
            let current = self.current;
            if !current.is_null() {
                unsafe {
                    self.current = (*current).next;
                    Some($constructor(current))
                }
            } else {
                None
            }
        }
    };
    ($item:ty) => (list_iterator!($item, $item::from_raw));
}

macro_rules! ffi_enum_wrapper {
    ($(#[$Attr:meta])* pub enum $Name:ident: $T:ty {
        $($(#[$ItemAttr:meta])* $Item:ident = $Value:expr),+
    }) => {
        #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
        $(#[$Attr])*
        pub struct $Name($T);

        $(pub const $Item: $Name = $Name($Value as $T);)+

        impl $Name {
            pub unsafe fn from_raw(raw: $T) -> $Name {
                $Name(raw)
            }

            pub fn raw(&self) -> $T {
                self.0
            }
        }
    };
    ($(#[$Attr:meta])* pub enum $Name:ident: $T:ty {
        $($(#[$ItemAttr:meta])* $Item:ident = $Value:expr,)+
    }) => {
        ffi_enum_wrapper! {
            $(#[$Attr])*
            pub enum $Name: $T {
                $($(#[$ItemAttr])* $Item = $Value),+
            }
        }
    };
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StrError<'a> {
    NotPresent,
    NotUtf8(&'a CStr, Utf8Error),
}

pub type StrResult<'a> = Result<&'a str, StrError<'a>>;

impl<'a> fmt::Display for StrError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StrError::NotPresent => write!(f, "no string present"),
            StrError::NotUtf8(ref s, _) => {
                write!(f, "string was not valid utf-8: {:?}", s)
            }
        }
    }
}

impl<'a> error::Error for StrError<'a> {
    fn description(&self) -> &str {
        match *self {
            StrError::NotPresent => "no string present",
            StrError::NotUtf8(..) => "string was not valid utf-8",
        }
    }
}

pub unsafe fn from_cstr<'a>(s: *const libc::c_char) -> StrResult<'a> {
    if !s.is_null() {
        let s = CStr::from_ptr(s);
        s.to_str().map_err(|e| StrError::NotUtf8(s, e))
    } else {
        Err(StrError::NotPresent)
    }
}

pub struct FdWriter {
    fd: libc::c_int,
}

impl FdWriter {
    pub unsafe fn new(fd: libc::c_int) -> FdWriter {
        FdWriter { fd: fd }
    }
}

impl Write for FdWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let result = unsafe {
            ffi::gpgme_io_write(self.fd, buf.as_ptr() as *const _, buf.len() as libc::size_t)
        };
        if result >= 0 {
            Ok(result as usize)
        } else {
            Err(Error::last_os_error().into())
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}
<commit_msg>Improve debug output for wrapped ffi enums<commit_after>use std::error;
use std::ffi::CStr;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::str::Utf8Error;

use libc;
use ffi;

use error::Error;

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

macro_rules! list_iterator {
    ($item:ty, $constructor:path) => {
        type Item = $item;

        fn next(&mut self) -> Option<Self::Item> {
            let current = self.current;
            if !current.is_null() {
                unsafe {
                    self.current = (*current).next;
                    Some($constructor(current))
                }
            } else {
                None
            }
        }
    };
    ($item:ty) => (list_iterator!($item, $item::from_raw));
}

macro_rules! ffi_enum_wrapper {
    ($(#[$Attr:meta])* pub enum $Name:ident: $T:ty {
        $($(#[$ItemAttr:meta])* $Item:ident = $Value:expr),+
    }) => {
        #[derive(Copy, Clone, Eq, PartialEq, Hash)]
        $(#[$Attr])*
        pub struct $Name($T);

        $(pub const $Item: $Name = $Name($Value as $T);)+

        impl $Name {
            pub unsafe fn from_raw(raw: $T) -> $Name {
                $Name(raw)
            }

            pub fn raw(&self) -> $T {
                self.0
            }
        }

        impl ::std::fmt::Debug for $Name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match *self {
                    $($Item => write!(f, concat!(stringify!($Item), "({})"), self.0),)+
                    _ => write!(f, concat!(stringify!($Name), "({})"), self.0),
                }
            }
        }
    };
    ($(#[$Attr:meta])* pub enum $Name:ident: $T:ty {
        $($(#[$ItemAttr:meta])* $Item:ident = $Value:expr,)+
    }) => {
        ffi_enum_wrapper! {
            $(#[$Attr])*
            pub enum $Name: $T {
                $($(#[$ItemAttr])* $Item = $Value),+
            }
        }
    };
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StrError<'a> {
    NotPresent,
    NotUtf8(&'a CStr, Utf8Error),
}

pub type StrResult<'a> = Result<&'a str, StrError<'a>>;

impl<'a> fmt::Display for StrError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StrError::NotPresent => write!(f, "no string present"),
            StrError::NotUtf8(ref s, _) => {
                write!(f, "string was not valid utf-8: {:?}", s)
            }
        }
    }
}

impl<'a> error::Error for StrError<'a> {
    fn description(&self) -> &str {
        match *self {
            StrError::NotPresent => "no string present",
            StrError::NotUtf8(..) => "string was not valid utf-8",
        }
    }
}

pub unsafe fn from_cstr<'a>(s: *const libc::c_char) -> StrResult<'a> {
    if !s.is_null() {
        let s = CStr::from_ptr(s);
        s.to_str().map_err(|e| StrError::NotUtf8(s, e))
    } else {
        Err(StrError::NotPresent)
    }
}

pub struct FdWriter {
    fd: libc::c_int,
}

impl FdWriter {
    pub unsafe fn new(fd: libc::c_int) -> FdWriter {
        FdWriter { fd: fd }
    }
}

impl Write for FdWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let result = unsafe {
            ffi::gpgme_io_write(self.fd, buf.as_ptr() as *const _, buf.len() as libc::size_t)
        };
        if result >= 0 {
            Ok(result as usize)
        } else {
            Err(Error::last_os_error().into())
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::time::{Duration, Instant};

use regex::{Captures, Regex};

use console::{measure_text_width, Style};

pub fn duration_to_secs(d: Duration) -> f64 {
    d.as_secs() as f64 + f64::from(d.subsec_nanos()) / 1_000_000_000f64
}

pub fn secs_to_duration(s: f64) -> Duration {
    let secs = s.trunc() as u64;
    let nanos = (s.fract() * 1_000_000_000f64) as u32;
    Duration::new(secs, nanos)
}

pub struct Estimate {
    buf: Box<[f64; 15]>,
    data: u8,
    started: Option<(Instant, u64)>,
}

impl Estimate {
    fn len(&self) -> u8 {
        self.data & 0x0F
    }

    fn set_len(&mut self, len: u8) {
        // Sanity check to make sure math is correct as otherwise it could result in unexpected bugs
        debug_assert!(len < 16);
        self.data = (self.data & 0xF0) | len;
    }

    fn last_idx(&self) -> u8 {
        (self.data & 0xF0) >> 4
    }

    fn set_last_idx(&mut self, last_idx: u8) {
        // This will wrap last_idx on overflow (setting to 16 will result in 0); this is fine
        // because Estimate::buf is 15 elements long
        self.data = ((last_idx & 0x0F) << 4) | (self.data & 0x0F);
    }

    pub fn new() -> Self {
        let this = Self {
            buf: Box::new([0.0; 15]),
            data: 0,
            started: Some((<Instant>::now(), 0)),
        };
        // Make sure not to break anything accidentally as self.data can't handle bufs longer than
        // 15 elements
        debug_assert!(this.buf.len() < 16);
        this
    }

    pub fn reset(&mut self) {
        self.started = None;
        self.data = 0;
    }

    pub fn record_step(&mut self, value: u64) {
        // record initial position
        let (started_time, started_value) =
            *self.started.get_or_insert_with(|| (Instant::now(), value));

        let item = {
            let divisor = value.saturating_sub(started_value) as f64;
            if divisor == 0.0 {
                0.0
            } else {
                duration_to_secs(started_time.elapsed()) / divisor
            }
        };
        let len = self.len();
        let last_idx = self.last_idx();
        if self.buf.len() <= usize::from(len) {
            let idx = last_idx % len;
            self.buf[usize::from(idx)] = item;
        } else {
            self.set_len(len + 1);
            self.buf[usize::from(last_idx)] = item;
        }
        self.set_last_idx(last_idx + 1);
    }

    pub fn time_per_step(&self) -> Duration {
        let len = self.len();
        secs_to_duration(self.buf[0..usize::from(len)].iter().sum::<f64>() / f64::from(len))
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum Alignment {
    Left,
    Center,
    Right,
}

#[derive(Debug)]
pub struct TemplateVar<'a> {
    pub key: &'a str,
    pub align: Alignment,
    pub truncate: bool,
    pub width: Option<usize>,
    pub style: Option<Style>,
    pub alt_style: Option<Style>,
    pub last_element: bool,
}

impl<'a> TemplateVar<'a> {
    pub fn duplicate_for_key<'b>(&self, key: &'b str) -> TemplateVar<'b> {
        TemplateVar {
            key,
            align: self.align,
            truncate: self.truncate,
            width: self.width,
            style: self.style.clone(),
            alt_style: self.alt_style.clone(),
            last_element: self.last_element,
        }
    }
}

pub fn expand_template<F: FnMut(&TemplateVar<'_>) -> String>(s: &str, mut f: F) -> Cow<'_, str> {
    lazy_static::lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"(\}\})|\{(\{|[^{}}]+\})").unwrap();
        static ref KEY_RE: Regex = Regex::new(
            r"(?x)
                ([^:]+)
                (?:
                    :
                    ([<^>])?
                    ([0-9]+)?
                    (!)?
                    (?:\.([a-z_]+(?:\.[a-z_]+)*))?
                    (?:/([a-z_]+(?:\.[a-z_]+)*))?
                )?
            "
        )
        .unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        if caps.get(1).is_some() {
            return "}".into();
        }
        let key = &caps[2];
        if key == "{" {
            return "{".into();
        }
        let mut var = TemplateVar {
            key,
            align: Alignment::Left,
            truncate: false,
            width: None,
            style: None,
            alt_style: None,
            last_element: caps.get(0).unwrap().end() >= s.len(),
        };
        if let Some(opt_caps) = KEY_RE.captures(&key[..key.len() - 1]) {
            if let Some(short_key) = opt_caps.get(1) {
                var.key = short_key.as_str();
            }
            var.align = match opt_caps.get(2).map(|x| x.as_str()) {
                Some("<") => Alignment::Left,
                Some("^") => Alignment::Center,
                Some(">") => Alignment::Right,
                _ => Alignment::Left,
            };
            if let Some(width) = opt_caps.get(3) {
                var.width = Some(width.as_str().parse().unwrap());
            }
            if opt_caps.get(4).is_some() {
                var.truncate = true;
            }
            if let Some(style) = opt_caps.get(5) {
                var.style = Some(Style::from_dotted_str(style.as_str()));
            }
            if let Some(alt_style) = opt_caps.get(6) {
                var.alt_style = Some(Style::from_dotted_str(alt_style.as_str()));
            }
        }
        let mut rv = f(&var);
        if let Some(width) = var.width {
            rv = pad_str(&rv, width, var.align, var.truncate).to_string()
        }
        if let Some(s) = var.style {
            rv = s.apply_to(rv).to_string();
        }
        rv
    })
}

pub fn pad_str(s: &str, width: usize, align: Alignment, truncate: bool) -> Cow<'_, str> {
    let cols = measure_text_width(s);

    if cols >= width {
        return if truncate {
            Cow::Borrowed(s.get(..width).unwrap_or(s))
        } else {
            Cow::Borrowed(s)
        };
    }

    let diff = width.saturating_sub(cols);

    let (left_pad, right_pad) = match align {
        Alignment::Left => (0, diff),
        Alignment::Right => (diff, 0),
        Alignment::Center => (diff / 2, diff.saturating_sub(diff / 2)),
    };

    let mut rv = String::new();
    for _ in 0..left_pad {
        rv.push(' ');
    }
    rv.push_str(s);
    for _ in 0..right_pad {
        rv.push(' ');
    }
    Cow::Owned(rv)
}

#[test]
fn test_expand_template() {
    let rv = expand_template("{{ {foo} {bar} }}", |var| var.key.to_uppercase());
    assert_eq!(&rv, "{ FOO BAR }");
    let rv = expand_template(r#"{ "foo": "{foo}", "bar": {bar} }"#, |var| {
        var.key.to_uppercase()
    });
    assert_eq!(&rv, r#"{ "foo": "FOO", "bar": BAR }"#);
}

#[test]
fn test_expand_template_flags() {
    use console::set_colors_enabled;
    set_colors_enabled(true);

    let rv = expand_template("{foo:5}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        "XXX".into()
    });
    assert_eq!(&rv, "XXX  ");

    let rv = expand_template("{foo:.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, None);
        assert_eq!(var.align, Alignment::Left);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44mXXX\u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue/green.on_cyan}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        assert_eq!(var.alt_style, Some(Style::new().green().on_cyan()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");
}

#[test]
fn test_duration_stuff() {
    let duration = Duration::new(42, 100_000_000);
    let secs = duration_to_secs(duration);
    assert_eq!(secs_to_duration(secs), duration);
}
<commit_msg>Expand Estimate docs<commit_after>use std::borrow::Cow;
use std::time::{Duration, Instant};

use regex::{Captures, Regex};

use console::{measure_text_width, Style};

pub fn duration_to_secs(d: Duration) -> f64 {
    d.as_secs() as f64 + f64::from(d.subsec_nanos()) / 1_000_000_000f64
}

pub fn secs_to_duration(s: f64) -> Duration {
    let secs = s.trunc() as u64;
    let nanos = (s.fract() * 1_000_000_000f64) as u32;
    Duration::new(secs, nanos)
}

/// Ring buffer with constant capacity
pub struct Estimate {
    buf: Box<[f64; 15]>,
    /// Lower 4 bits signify the current length, meaning how many values of `buf` are actually
    /// meaningful (and not just set to 0 by initialization).
    ///
    /// The upper 4 bits signify the last used index in the `buf`. The estimate is currently
    /// implemented as a ring buffer and when recording a new step the oldest value is overwritten.
    /// Last index is the most recently used position, and as elements are always stored with
    /// insertion order, `last_index + 1` is the least recently used position and is the first
    /// to be overwritten.
    data: u8,
    started: Option<(Instant, u64)>,
}

impl Estimate {
    fn len(&self) -> u8 {
        self.data & 0x0F
    }

    fn set_len(&mut self, len: u8) {
        // Sanity check to make sure math is correct as otherwise it could result in unexpected bugs
        debug_assert!(len < 16);
        self.data = (self.data & 0xF0) | len;
    }

    fn last_idx(&self) -> u8 {
        (self.data & 0xF0) >> 4
    }

    fn set_last_idx(&mut self, last_idx: u8) {
        // This will wrap last_idx on overflow (setting to 16 will result in 0); this is fine
        // because Estimate::buf is 15 elements long and this is a ring buffer, so overwriting
        // the oldest value is correct
        self.data = ((last_idx & 0x0F) << 4) | (self.data & 0x0F);
    }

    pub fn new() -> Self {
        let this = Self {
            buf: Box::new([0.0; 15]),
            data: 0,
            started: Some((<Instant>::now(), 0)),
        };
        // Make sure not to break anything accidentally as self.data can't handle bufs longer than
        // 15 elements (not enough space in a u8)
        debug_assert!(this.buf.len() < 16);
        this
    }

    pub fn reset(&mut self) {
        self.started = None;
        self.data = 0;
    }

    pub fn record_step(&mut self, value: u64) {
        // record initial position
        let (started_time, started_value) =
            *self.started.get_or_insert_with(|| (Instant::now(), value));

        let item = {
            let divisor = value.saturating_sub(started_value) as f64;
            if divisor == 0.0 {
                0.0
            } else {
                duration_to_secs(started_time.elapsed()) / divisor
            }
        };

        self.push(item);
    }

    /// Adds the `value` into the buffer, overwriting the oldest one if full, or increasing length
    /// by 1 and appending otherwise.
    fn push(&mut self, value: f64) {
        let len = self.len();
        let last_idx = self.last_idx();

        if self.buf.len() > usize::from(len) {
            // Buffer isn't yet full, increase it's size
            self.set_len(len + 1);
            self.buf[usize::from(last_idx)] = value;
        } else {
            // Buffer is full, overwrite the oldest value
            let idx = last_idx % len;
            self.buf[usize::from(idx)] = value;
        }

        self.set_last_idx(last_idx + 1);
    }

    pub fn time_per_step(&self) -> Duration {
        let len = self.len();
        secs_to_duration(self.buf[0..usize::from(len)].iter().sum::<f64>() / f64::from(len))
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum Alignment {
    Left,
    Center,
    Right,
}

#[derive(Debug)]
pub struct TemplateVar<'a> {
    pub key: &'a str,
    pub align: Alignment,
    pub truncate: bool,
    pub width: Option<usize>,
    pub style: Option<Style>,
    pub alt_style: Option<Style>,
    pub last_element: bool,
}

impl<'a> TemplateVar<'a> {
    pub fn duplicate_for_key<'b>(&self, key: &'b str) -> TemplateVar<'b> {
        TemplateVar {
            key,
            align: self.align,
            truncate: self.truncate,
            width: self.width,
            style: self.style.clone(),
            alt_style: self.alt_style.clone(),
            last_element: self.last_element,
        }
    }
}

pub fn expand_template<F: FnMut(&TemplateVar<'_>) -> String>(s: &str, mut f: F) -> Cow<'_, str> {
    lazy_static::lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"(\}\})|\{(\{|[^{}}]+\})").unwrap();
        static ref KEY_RE: Regex = Regex::new(
            r"(?x)
                ([^:]+)
                (?:
                    :
                    ([<^>])?
                    ([0-9]+)?
                    (!)?
                    (?:\.([a-z_]+(?:\.[a-z_]+)*))?
                    (?:/([a-z_]+(?:\.[a-z_]+)*))?
                )?
            "
        )
        .unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        if caps.get(1).is_some() {
            return "}".into();
        }
        let key = &caps[2];
        if key == "{" {
            return "{".into();
        }
        let mut var = TemplateVar {
            key,
            align: Alignment::Left,
            truncate: false,
            width: None,
            style: None,
            alt_style: None,
            last_element: caps.get(0).unwrap().end() >= s.len(),
        };
        if let Some(opt_caps) = KEY_RE.captures(&key[..key.len() - 1]) {
            if let Some(short_key) = opt_caps.get(1) {
                var.key = short_key.as_str();
            }
            var.align = match opt_caps.get(2).map(|x| x.as_str()) {
                Some("<") => Alignment::Left,
                Some("^") => Alignment::Center,
                Some(">") => Alignment::Right,
                _ => Alignment::Left,
            };
            if let Some(width) = opt_caps.get(3) {
                var.width = Some(width.as_str().parse().unwrap());
            }
            if opt_caps.get(4).is_some() {
                var.truncate = true;
            }
            if let Some(style) = opt_caps.get(5) {
                var.style = Some(Style::from_dotted_str(style.as_str()));
            }
            if let Some(alt_style) = opt_caps.get(6) {
                var.alt_style = Some(Style::from_dotted_str(alt_style.as_str()));
            }
        }
        let mut rv = f(&var);
        if let Some(width) = var.width {
            rv = pad_str(&rv, width, var.align, var.truncate).to_string()
        }
        if let Some(s) = var.style {
            rv = s.apply_to(rv).to_string();
        }
        rv
    })
}

pub fn pad_str(s: &str, width: usize, align: Alignment, truncate: bool) -> Cow<'_, str> {
    let cols = measure_text_width(s);

    if cols >= width {
        return if truncate {
            Cow::Borrowed(s.get(..width).unwrap_or(s))
        } else {
            Cow::Borrowed(s)
        };
    }

    let diff = width.saturating_sub(cols);

    let (left_pad, right_pad) = match align {
        Alignment::Left => (0, diff),
        Alignment::Right => (diff, 0),
        Alignment::Center => (diff / 2, diff.saturating_sub(diff / 2)),
    };

    let mut rv = String::new();
    for _ in 0..left_pad {
        rv.push(' ');
    }
    rv.push_str(s);
    for _ in 0..right_pad {
        rv.push(' ');
    }
    Cow::Owned(rv)
}

#[test]
fn test_expand_template() {
    let rv = expand_template("{{ {foo} {bar} }}", |var| var.key.to_uppercase());
    assert_eq!(&rv, "{ FOO BAR }");
    let rv = expand_template(r#"{ "foo": "{foo}", "bar": {bar} }"#, |var| {
        var.key.to_uppercase()
    });
    assert_eq!(&rv, r#"{ "foo": "FOO", "bar": BAR }"#);
}

#[test]
fn test_expand_template_flags() {
    use console::set_colors_enabled;
    set_colors_enabled(true);

    let rv = expand_template("{foo:5}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        "XXX".into()
    });
    assert_eq!(&rv, "XXX  ");

    let rv = expand_template("{foo:.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, None);
        assert_eq!(var.align, Alignment::Left);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44mXXX\u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");

    let rv = expand_template("{foo:^5.red.on_blue/green.on_cyan}", |var| {
        assert_eq!(var.key, "foo");
        assert_eq!(var.width, Some(5));
        assert_eq!(var.align, Alignment::Center);
        assert_eq!(var.style, Some(Style::new().red().on_blue()));
        assert_eq!(var.alt_style, Some(Style::new().green().on_cyan()));
        "XXX".into()
    });
    assert_eq!(&rv, "\u{1b}[31m\u{1b}[44m XXX \u{1b}[0m");
}

#[test]
fn test_duration_stuff() {
    let duration = Duration::new(42, 100_000_000);
    let secs = duration_to_secs(duration);
    assert_eq!(secs_to_duration(secs), duration);
}
<|endoftext|>


<commit_before>use libc::{c_uint, c_int};
use ffi::prelude::LLVMValueRef;
use ffi::core;
use std::ffi::CString;
use std::{fmt, mem};
use std::ops::{Deref, Index};
use block::BasicBlock;
use context::{Context, GetContext};
use ty::{FunctionType, Type};
use util;

/// A typed value that can be used as an operand in instructions
pub struct Value;
native_ref!(&Value = LLVMValueRef);
impl Index<usize> for Value {
    type Output = Value;
    fn index(&self, index: usize) -> &Value {
        unsafe {
            if index < core::LLVMCountParams(self.into()) as usize {
                core::LLVMGetParam(self.into(), index as c_uint).into()
            } else {
                panic!("no such index {} on {:?}", index, self.get_type())
            }
        }
    }
}
impl Value {
    pub fn new_struct<'a>(context: &'a Context, vals: &[&'a Value], packed: bool) -> &'a Value {
        unsafe { core::LLVMConstStructInContext(context.into(), vals.as_ptr() as *mut LLVMValueRef, vals.len() as c_uint, packed as c_int) }.into()
    }
    pub fn get_name(&self) -> Option<&str> {
        unsafe {
            let c_name = core::LLVMGetValueName(self.into());
            util::to_null_str(c_name as *mut i8)
        }
    }
    pub fn set_name(&self, name: &str) {
        let c_name = CString::new(name).unwrap();
        unsafe {
            core::LLVMSetValueName(self.into(), c_name.as_ptr())
        }
    }
    pub fn get_type(&self) -> &Type {
        unsafe { core::LLVMTypeOf(self.into()) }.into()
    }
}
/// A `Value` that represents a `Function`
pub struct Function;
native_ref!(&Function = LLVMValueRef);
impl Deref for Function {
    type Target = Value;
    fn deref(&self) -> &Value {
        unsafe { mem::transmute(self) }
    }
}
impl Function {
    pub fn append<'a>(&'a self, name: &str) -> &'a BasicBlock {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAppendBasicBlockInContext(self.get_context().into(), self.into(), ptr).into()
        })
    }
    pub fn get_entry(&self) -> Option<&BasicBlock> {
        unsafe { mem::transmute(core::LLVMGetEntryBasicBlock(self.into())) }
    }

    pub fn get_name(&self) -> &str {
        unsafe {
            let c_name = core::LLVMGetValueName(self.into());
            util::to_str(c_name as *mut i8)
        }
    }
    pub fn get_signature(&self) -> &FunctionType {
        unsafe { core::LLVMTypeOf(self.into()) }.into()
    }
}
impl GetContext for Value {
    fn get_context(&self) -> &Context {
        self.get_type().get_context()
    }
}
to_str!(Value, LLVMPrintValueToString);
<commit_msg>Add more docs<commit_after>use libc::{c_uint, c_int};
use ffi::prelude::LLVMValueRef;
use ffi::core;
use std::ffi::CString;
use std::{fmt, mem};
use std::ops::{Deref, Index};
use block::BasicBlock;
use context::{Context, GetContext};
use ty::{FunctionType, Type};
use util;

/// A typed value that can be used as an operand in instructions
pub struct Value;
native_ref!(&Value = LLVMValueRef);
impl Index<usize> for Value {
    type Output = Value;
    fn index(&self, index: usize) -> &Value {
        unsafe {
            if index < core::LLVMCountParams(self.into()) as usize {
                core::LLVMGetParam(self.into(), index as c_uint).into()
            } else {
                panic!("no such index {} on {:?}", index, self.get_type())
            }
        }
    }
}
impl Value {
    /// Create a new constant struct from the values given
    pub fn new_struct<'a>(context: &'a Context, vals: &[&'a Value], packed: bool) -> &'a Value {
        unsafe { core::LLVMConstStructInContext(context.into(), vals.as_ptr() as *mut LLVMValueRef, vals.len() as c_uint, packed as c_int) }.into()
    }
    pub fn get_name(&self) -> Option<&str> {
        unsafe {
            let c_name = core::LLVMGetValueName(self.into());
            util::to_null_str(c_name as *mut i8)
        }
    }
    pub fn set_name(&self, name: &str) {
        let c_name = CString::new(name).unwrap();
        unsafe {
            core::LLVMSetValueName(self.into(), c_name.as_ptr())
        }
    }
    pub fn get_type(&self) -> &Type {
        unsafe { core::LLVMTypeOf(self.into()) }.into()
    }
}
/// A `Value` that represents a `Function`
pub struct Function;
native_ref!(&Function = LLVMValueRef);
impl Deref for Function {
    type Target = Value;
    fn deref(&self) -> &Value {
        unsafe { mem::transmute(self) }
    }
}
impl Function {
    pub fn append<'a>(&'a self, name: &str) -> &'a BasicBlock {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAppendBasicBlockInContext(self.get_context().into(), self.into(), ptr).into()
        })
    }
    pub fn get_entry(&self) -> Option<&BasicBlock> {
        unsafe { mem::transmute(core::LLVMGetEntryBasicBlock(self.into())) }
    }

    pub fn get_name(&self) -> &str {
        unsafe {
            let c_name = core::LLVMGetValueName(self.into());
            util::to_str(c_name as *mut i8)
        }
    }
    pub fn get_signature(&self) -> &FunctionType {
        unsafe { core::LLVMTypeOf(self.into()) }.into()
    }
}
impl GetContext for Value {
    fn get_context(&self) -> &Context {
        self.get_type().get_context()
    }
}
to_str!(Value, LLVMPrintValueToString);
<|endoftext|>


<commit_before>// Copyright 2014 The HTML5 for Rust Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unused_imports)]  // for quotes

use syntax::codemap::Span;
use syntax::ast::{TokenTree, TTTok};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, LIT_STR, IDENT};

use std::iter::Chain;
use std::slice::Items;
use std::gc::Gc;

mod data;

fn all_atoms<'a>() -> Chain<Items<'a, &'static str>, Items<'a, &'static str>> {
    data::fast_set_atoms.iter().chain(data::other_atoms.iter())
}

// Build a PhfMap yielding static atom IDs.
// Takes no arguments.
pub fn expand_static_atom_map(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = all_atoms().enumerate().flat_map(|(i, k)|
        quote_tokens!(&mut *cx, $k => $i,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_map!($tts)))
}

// Build the array to convert IDs back to strings.
// FIXME: share storage with the PhfMap keys.
pub fn expand_static_atom_array(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, sp, "Usage: static_atom_array!()");
    let tts: Vec<TokenTree> = all_atoms().flat_map(|k|
        quote_tokens!(&mut *cx, $k,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, &[$tts]))
}

fn find_atom(t: &TokenTree) -> Option<uint> {
    let s = get_ident(match *t {
        TTTok(_, IDENT(s, _)) => s,
        TTTok(_, LIT_STR(s)) => s,
        _ => return None,
    });

    // Use bsearch instead of bsearch_elem because of type mismatch
    // between &'t str and &'static str.
    data::fast_set_atoms.bsearch(|&x| x.cmp(&s.get())).or_else(||
        data::other_atoms.bsearch(|&x| x.cmp(&s.get())).map(|i| i+64))
}

struct AtomResult {
    expr: Gc<ast::Expr>,
    pat: Gc<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        Some(self.pat)
    }
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
pub fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let i = match tt {
        [ref t] => expect!(sp, find_atom(t), usage),
        _ => bail!(sp, usage),
    };

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::util::atom::Static($i)),
        pat: quote_pat!(&mut *cx, ::util::atom::Static($i)),
    } as Box<MacResult>
}
<commit_msg>Better error message on atom!() lookup failure<commit_after>// Copyright 2014 The HTML5 for Rust Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unused_imports)]  // for quotes

use syntax::codemap::Span;
use syntax::ast::{TokenTree, TTTok};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, InternedString, LIT_STR, IDENT};

use std::iter::Chain;
use std::slice::Items;
use std::gc::Gc;

mod data;

fn all_atoms<'a>() -> Chain<Items<'a, &'static str>, Items<'a, &'static str>> {
    data::fast_set_atoms.iter().chain(data::other_atoms.iter())
}

// Build a PhfMap yielding static atom IDs.
// Takes no arguments.
pub fn expand_static_atom_map(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = all_atoms().enumerate().flat_map(|(i, k)|
        quote_tokens!(&mut *cx, $k => $i,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_map!($tts)))
}

// Build the array to convert IDs back to strings.
// FIXME: share storage with the PhfMap keys.
pub fn expand_static_atom_array(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, sp, "Usage: static_atom_array!()");
    let tts: Vec<TokenTree> = all_atoms().flat_map(|k|
        quote_tokens!(&mut *cx, $k,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, &[$tts]))
}

fn atom_tok_to_str(t: &TokenTree) -> Option<InternedString> {
    Some(get_ident(match *t {
        TTTok(_, IDENT(s, _)) => s,
        TTTok(_, LIT_STR(s)) => s,
        _ => return None,
    }))
}

fn find_atom(name: InternedString) -> Option<uint> {
    // Use bsearch instead of bsearch_elem because of type mismatch
    // between &'t str and &'static str.
    data::fast_set_atoms.bsearch(|&x| x.cmp(&name.get())).or_else(||
        data::other_atoms.bsearch(|&x| x.cmp(&name.get())).map(|i| i+64))
}

struct AtomResult {
    expr: Gc<ast::Expr>,
    pat: Gc<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        Some(self.pat)
    }
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
pub fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let name = match tt {
        [ref t] => expect!(sp, atom_tok_to_str(t), usage),
        _ => bail!(sp, usage),
    };

    let i = expect!(sp, find_atom(name.clone()),
        format!("Unknown static atom {:s}", name.get()).as_slice());

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::util::atom::Static($i)),
        pat: quote_pat!(&mut *cx, ::util::atom::Static($i)),
    } as Box<MacResult>
}
<|endoftext|>


<commit_before>pub type c_long = i64;
pub type c_ulong = u64;
pub type c_char = u8;

// should be pub(crate), but that requires Rust 1.18.0
cfg_if! {
    if #[cfg(libc_const_size_of)] {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_double>() - 1;
    } else {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = 8 - 1;
    }
}

pub const _MAX_PAGE_SHIFT: u32 = 12;
<commit_msg>correct arm c_long size<commit_after>pub type c_long = i32;
pub type c_ulong = u32;
pub type c_char = u8;

// should be pub(crate), but that requires Rust 1.18.0
cfg_if! {
    if #[cfg(libc_const_size_of)] {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_double>() - 1;
    } else {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = 8 - 1;
    }
}

pub const _MAX_PAGE_SHIFT: u32 = 12;
<|endoftext|>


<commit_before>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
    state: Option<State>,
    new_game: bool,
    exit: bool,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path), new_game: false, exit: false, }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        handle_on_update(&mut self.ui, &mut self.new_game, &mut self.exit);
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}

fn handle_on_update(ui: &mut conrod::Ui<piston_window::Glyphs>, new_game: &mut bool, exit: &mut bool) {
    ui.set_widgets(|ui| {
        conrod::Canvas::new()
            .pad(30.)
            .color(conrod::color::rgb(0.2, 0.35, 0.45))
            .scroll_kids()
            .set(CANVAS, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .rgb(0.4, 0.75, 0.6)
            .label("New game")
            .react(|| *new_game = true)
            .set(NEW_GAME_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(NEW_GAME_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Options")
            .react(|| ())
            .set(OPTIONS_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(OPTIONS_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Exit")
            .react(|| *exit = true)
            .set(EXIT_BUTTON, ui);
    });
}
<commit_msg>MainMenu: state instead of flags<commit_after>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
    state: Option<State>,
    new_game: bool,
    exit: bool,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path), state: None, new_game: false, exit: false, }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        handle_on_update(&mut self.ui, &mut self.state);
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}

fn handle_on_update(ui: &mut conrod::Ui<piston_window::Glyphs>, state: &mut Option<State>) {
    ui.set_widgets(|ui| {
        conrod::Canvas::new()
            .pad(30.)
            .color(conrod::color::rgb(0.2, 0.35, 0.45))
            .scroll_kids()
            .set(CANVAS, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .rgb(0.4, 0.75, 0.6)
            .label("New game")
            .react(|| *state = Some(State::NewGame))
            .set(NEW_GAME_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(NEW_GAME_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Options")
            .react(|| *state = Some(State::Options))
            .set(OPTIONS_BUTTON, ui);

        conrod::Button::new()
            .w_h(200.0, 50.0)
            .mid_left_of(CANVAS)
            .down_from(OPTIONS_BUTTON, 45.0)
            .rgb(0.4, 0.75, 0.6)
            .label("Exit")
            .react(|| *state = Some(State::Exit))
            .set(EXIT_BUTTON, ui);
    });
}
<|endoftext|>


<commit_before>extern crate xxhash;

#[inline]
pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
    d2 + f1 * d1 + f2
}

#[inline]
fn split(hash: u64) -> (u32, u32, u32) {
    let bits = 21;
    let mask = (1 << bits) - 1;

    ((hash & mask) as u32,
     ((hash >> bits) & mask) as u32,
     ((hash >> (2 * bits)) & mask) as u32)
}

/// A trait implemented by types which can be used in PHF data structures
pub trait PhfHash {
    /// Hashes the value of `self`, factoring in a seed
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32);
}

impl<'a> PhfHash for &'a str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        split(xxhash::hash_with_seed(seed, self))
    }
}

impl<'a> PhfHash for &'a [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        split(xxhash::oneshot(*self, seed))
    }
}

macro_rules! sip_impl(
    ($t:ty) => (
        impl PhfHash for $t {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                split(xxhash::hash_with_seed(seed, self))
            }
        }
    )
)

sip_impl!(u8)
sip_impl!(i8)
sip_impl!(u16)
sip_impl!(i16)
sip_impl!(u32)
sip_impl!(i32)
sip_impl!(u64)
sip_impl!(i64)
sip_impl!(char)
sip_impl!(bool)
<commit_msg>Make some values consts<commit_after>extern crate xxhash;

#[inline]
pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
    d2 + f1 * d1 + f2
}

#[inline]
fn split(hash: u64) -> (u32, u32, u32) {
    const BITS: uint = 21;
    const MASK: u64 = (1 << BITS) - 1;

    ((hash & MASK) as u32,
     ((hash >> BITS) & MASK) as u32,
     ((hash >> (2 * BITS)) & MASK) as u32)
}

/// A trait implemented by types which can be used in PHF data structures
pub trait PhfHash {
    /// Hashes the value of `self`, factoring in a seed
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32);
}

impl<'a> PhfHash for &'a str {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        split(xxhash::hash_with_seed(seed, self))
    }
}

impl<'a> PhfHash for &'a [u8] {
    #[inline]
    fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
        split(xxhash::oneshot(*self, seed))
    }
}

macro_rules! sip_impl(
    ($t:ty) => (
        impl PhfHash for $t {
            #[inline]
            fn phf_hash(&self, seed: u64) -> (u32, u32, u32) {
                split(xxhash::hash_with_seed(seed, self))
            }
        }
    )
)

sip_impl!(u8)
sip_impl!(i8)
sip_impl!(u16)
sip_impl!(i16)
sip_impl!(u32)
sip_impl!(i32)
sip_impl!(u64)
sip_impl!(i64)
sip_impl!(char)
sip_impl!(bool)
<|endoftext|>


<commit_before>// xfail-stage0
// -*- rust -*-

use std;
import std.deque;

fn test_simple() {
  let deque.t[int] d = deque.create[int]();
  check (d.size() == 0u);
  d.add_front(17);
  d.add_front(42);
  d.add_back(137);
  check (d.size() == 3u);
  d.add_back(137);
  check (d.size() == 4u);

  log d.peek_front();
  check (d.peek_front() == 42);

  log d.peek_back();
  check (d.peek_back() == 137);

  let int i = d.pop_front();
  log i;
  check (i == 42);

  i = d.pop_back();
  log i;
  check (i == 137);

  i = d.pop_back();
  log i;
  check (i == 137);

  i = d.pop_back();
  log i;
  check (i == 17);

  check (d.size() == 0u);
  d.add_back(3);
  check (d.size() == 1u);
  d.add_front(2);
  check (d.size() == 2u);
  d.add_back(4);
  check (d.size() == 3u);
  d.add_front(1);
  check (d.size() == 4u);

  log d.get(0);
  log d.get(1);
  log d.get(2);
  log d.get(3);

  check (d.get(0) == 1);
  check (d.get(1) == 2);
  check (d.get(2) == 3);
  check (d.get(3) == 4);
}

fn test_boxes(@int a, @int b, @int c, @int d) {
  let deque.t[@int] deq = deque.create[@int]();
  check (deq.size() == 0u);
  deq.add_front(a);
  deq.add_front(b);
  deq.add_back(c);
  check (deq.size() == 3u);
  deq.add_back(d);
  check (deq.size() == 4u);

  check (deq.peek_front() == b);
  check (deq.peek_back() == d);

  check (deq.pop_front() == b);
  check (deq.pop_back() == d);
  check (deq.pop_back() == c);
  check (deq.pop_back() == a);

  check (deq.size() == 0u);
  deq.add_back(c);
  check (deq.size() == 1u);
  deq.add_front(b);
  check (deq.size() == 2u);
  deq.add_back(d);
  check (deq.size() == 3u);
  deq.add_front(a);
  check (deq.size() == 4u);

  check (deq.get(0) == a);
  check (deq.get(1) == b);
  check (deq.get(2) == c);
  check (deq.get(3) == d);
}

type eqfn[T] = fn(T a, T b) -> bool;

fn test_parameterized[T](eqfn[T] e, &T a, &T b, &T c, &T d) {
  let deque.t[T] deq = deque.create[T]();
  check (deq.size() == 0u);
  deq.add_front(a);
  deq.add_front(b);
  deq.add_back(c);
  check (deq.size() == 3u);
  deq.add_back(d);
  check (deq.size() == 4u);

  check (e(deq.peek_front(), b));
  check (e(deq.peek_back(), d));

  check (e(deq.pop_front(), b));
  check (e(deq.pop_back(), d));
  check (e(deq.pop_back(), c));
  check (e(deq.pop_back(), a));

  check (deq.size() == 0u);
  deq.add_back(c);
  check (deq.size() == 1u);
  deq.add_front(b);
  check (deq.size() == 2u);
  deq.add_back(d);
  check (deq.size() == 3u);
  deq.add_front(a);
  check (deq.size() == 4u);

  check (e(deq.get(0), a));
  check (e(deq.get(1), b));
  check (e(deq.get(2), c));
  check (e(deq.get(3), d));
}

tag taggy {
  one(int);
  two(int, int);
  three(int, int, int);
}

tag taggypar[T] {
  onepar(int);
  twopar(int, int);
  threepar(int, int, int);
}

type reccy = rec(int x, int y, taggy t);

fn main() {
  fn inteq(int a, int b) -> bool {
    ret a == b;
  }

  fn intboxeq(@int a, @int b) -> bool {
    ret a == b;
  }

  fn taggyeq(taggy a, taggy b) -> bool {
    alt (a) {
      case (one(?a1)) {
        alt (b) {
          case (one(?b1)) { ret a1 == b1; }
          case (_) { ret false; }
        }
      }
      case (two(?a1, ?a2)) {
        alt (b) {
          case (two(?b1, ?b2)) { ret (a1 == b1 && a2 == b2); }
          case (_) { ret false; }
        }
      }
      case (three(?a1, ?a2, ?a3)) {
        alt (b) {
          case (three(?b1, ?b2, ?b3)) {
            ret (a1 == b1 && a2 == b2 && a3 == b3);
          }
          case (_) { ret false; }
        }
      }
    }
  }

  fn taggypareq[T](taggypar[T] a, taggypar[T] b) -> bool {
    alt (a) {
      case (onepar[T](?a1)) {
        alt (b) {
          case (onepar[T](?b1)) { ret a1 == b1; }
          case (_) { ret false; }
        }
      }
      case (twopar[T](?a1, ?a2)) {
        alt (b) {
          case (twopar[T](?b1, ?b2)) { ret (a1 == b1 && a2 == b2); }
          case (_) { ret false; }
        }
      }
      case (threepar[T](?a1, ?a2, ?a3)) {
        alt (b) {
          case (threepar[T](?b1, ?b2, ?b3)) {
            ret (a1 == b1 && a2 == b2 && a3 == b3);
          }
          case (_) { ret false; }
        }
      }
    }
  }

  fn reccyeq(reccy a, reccy b) -> bool {
    ret (a.x == b.x && a.y == b.y && taggyeq(a.t, b.t));
  }

  log "*** starting";

  log "*** test simple";
  test_simple();
  log "*** end test simple";

  /*
   * FIXME: Causes "Invalid read of size 4" under valgrind.

  log "*** test boxes";
  test_boxes(@5, @72, @64, @175);
  log "*** end test boxes";

   */

  log "test parameterized: int";
  let eqfn[int] eq1 = inteq;
  test_parameterized[int](eq1, 5, 72, 64, 175);

  /*
   * FIXME: Appears to segfault after an upcall_grow_task

  log "*** test parameterized: @int";
  let eqfn[@int] eq2 = intboxeq;
  test_parameterized[@int](eq2, @5, @72, @64, @175);
  log "*** end test parameterized @int";

  */

  log "test parameterized: taggy";
  let eqfn[taggy] eq3 = taggyeq;
  test_parameterized[taggy](eq3,
                            one(1), two(1, 2), three(1, 2, 3), two(17, 42));

  /*
   * FIXME: Segfault.  Also appears to be caused only after upcall_grow_task

  log "*** test parameterized: taggypar[int]";
  let eqfn[taggypar[int]] eq4 = taggypareq[int];
  test_parameterized[taggypar[int]](eq4,
                                    onepar[int](1),
                                    twopar[int](1, 2),
                                    threepar[int](1, 2, 3),
                                    twopar[int](17, 42));
  log "*** end test parameterized: taggypar[int]";

   */

  log "*** test parameterized: reccy";
  let reccy reccy1 = rec(x=1, y=2, t=one(1));
  let reccy reccy2 = rec(x=345, y=2, t=two(1, 2));
  let reccy reccy3 = rec(x=1, y=777, t=three(1, 2, 3));
  let reccy reccy4 = rec(x=19, y=252, t=two(17, 42));
  let eqfn[reccy] eq5 = reccyeq;
  test_parameterized[reccy](eq5,
                            reccy1, reccy2, reccy3, reccy4);
  log "*** end test parameterized: reccy";

  log "*** done";
}
<commit_msg>Fix lib-deque.rs to pass typarams by alias.<commit_after>// xfail-stage0
// -*- rust -*-

use std;
import std.deque;

fn test_simple() {
  let deque.t[int] d = deque.create[int]();
  check (d.size() == 0u);
  d.add_front(17);
  d.add_front(42);
  d.add_back(137);
  check (d.size() == 3u);
  d.add_back(137);
  check (d.size() == 4u);

  log d.peek_front();
  check (d.peek_front() == 42);

  log d.peek_back();
  check (d.peek_back() == 137);

  let int i = d.pop_front();
  log i;
  check (i == 42);

  i = d.pop_back();
  log i;
  check (i == 137);

  i = d.pop_back();
  log i;
  check (i == 137);

  i = d.pop_back();
  log i;
  check (i == 17);

  check (d.size() == 0u);
  d.add_back(3);
  check (d.size() == 1u);
  d.add_front(2);
  check (d.size() == 2u);
  d.add_back(4);
  check (d.size() == 3u);
  d.add_front(1);
  check (d.size() == 4u);

  log d.get(0);
  log d.get(1);
  log d.get(2);
  log d.get(3);

  check (d.get(0) == 1);
  check (d.get(1) == 2);
  check (d.get(2) == 3);
  check (d.get(3) == 4);
}

fn test_boxes(@int a, @int b, @int c, @int d) {
  let deque.t[@int] deq = deque.create[@int]();
  check (deq.size() == 0u);
  deq.add_front(a);
  deq.add_front(b);
  deq.add_back(c);
  check (deq.size() == 3u);
  deq.add_back(d);
  check (deq.size() == 4u);

  check (deq.peek_front() == b);
  check (deq.peek_back() == d);

  check (deq.pop_front() == b);
  check (deq.pop_back() == d);
  check (deq.pop_back() == c);
  check (deq.pop_back() == a);

  check (deq.size() == 0u);
  deq.add_back(c);
  check (deq.size() == 1u);
  deq.add_front(b);
  check (deq.size() == 2u);
  deq.add_back(d);
  check (deq.size() == 3u);
  deq.add_front(a);
  check (deq.size() == 4u);

  check (deq.get(0) == a);
  check (deq.get(1) == b);
  check (deq.get(2) == c);
  check (deq.get(3) == d);
}

type eqfn[T] = fn(&T a, &T b) -> bool;

fn test_parameterized[T](eqfn[T] e, &T a, &T b, &T c, &T d) {
  let deque.t[T] deq = deque.create[T]();
  check (deq.size() == 0u);
  deq.add_front(a);
  deq.add_front(b);
  deq.add_back(c);
  check (deq.size() == 3u);
  deq.add_back(d);
  check (deq.size() == 4u);

  check (e(deq.peek_front(), b));
  check (e(deq.peek_back(), d));

  check (e(deq.pop_front(), b));
  check (e(deq.pop_back(), d));
  check (e(deq.pop_back(), c));
  check (e(deq.pop_back(), a));

  check (deq.size() == 0u);
  deq.add_back(c);
  check (deq.size() == 1u);
  deq.add_front(b);
  check (deq.size() == 2u);
  deq.add_back(d);
  check (deq.size() == 3u);
  deq.add_front(a);
  check (deq.size() == 4u);

  check (e(deq.get(0), a));
  check (e(deq.get(1), b));
  check (e(deq.get(2), c));
  check (e(deq.get(3), d));
}

tag taggy {
  one(int);
  two(int, int);
  three(int, int, int);
}

tag taggypar[T] {
  onepar(int);
  twopar(int, int);
  threepar(int, int, int);
}

type reccy = rec(int x, int y, taggy t);

fn main() {
  fn inteq(&int a, &int b) -> bool {
    ret a == b;
  }

  fn intboxeq(&@int a, &@int b) -> bool {
    ret a == b;
  }

  fn taggyeq(&taggy a, &taggy b) -> bool {
    alt (a) {
      case (one(?a1)) {
        alt (b) {
          case (one(?b1)) { ret a1 == b1; }
          case (_) { ret false; }
        }
      }
      case (two(?a1, ?a2)) {
        alt (b) {
          case (two(?b1, ?b2)) { ret (a1 == b1 && a2 == b2); }
          case (_) { ret false; }
        }
      }
      case (three(?a1, ?a2, ?a3)) {
        alt (b) {
          case (three(?b1, ?b2, ?b3)) {
            ret (a1 == b1 && a2 == b2 && a3 == b3);
          }
          case (_) { ret false; }
        }
      }
    }
  }

  fn taggypareq[T](&taggypar[T] a, &taggypar[T] b) -> bool {
    alt (a) {
      case (onepar[T](?a1)) {
        alt (b) {
          case (onepar[T](?b1)) { ret a1 == b1; }
          case (_) { ret false; }
        }
      }
      case (twopar[T](?a1, ?a2)) {
        alt (b) {
          case (twopar[T](?b1, ?b2)) { ret (a1 == b1 && a2 == b2); }
          case (_) { ret false; }
        }
      }
      case (threepar[T](?a1, ?a2, ?a3)) {
        alt (b) {
          case (threepar[T](?b1, ?b2, ?b3)) {
            ret (a1 == b1 && a2 == b2 && a3 == b3);
          }
          case (_) { ret false; }
        }
      }
    }
  }

  fn reccyeq(&reccy a, &reccy b) -> bool {
    ret (a.x == b.x && a.y == b.y && taggyeq(a.t, b.t));
  }

  log "*** starting";

  log "*** test simple";
  test_simple();
  log "*** end test simple";

  /*
   * FIXME: Causes "Invalid read of size 4" under valgrind.

  log "*** test boxes";
  test_boxes(@5, @72, @64, @175);
  log "*** end test boxes";

   */

  log "test parameterized: int";
  let eqfn[int] eq1 = inteq;
  test_parameterized[int](eq1, 5, 72, 64, 175);

  /*
   * FIXME: Appears to segfault after an upcall_grow_task

  log "*** test parameterized: @int";
  let eqfn[@int] eq2 = intboxeq;
  test_parameterized[@int](eq2, @5, @72, @64, @175);
  log "*** end test parameterized @int";

  */

  log "test parameterized: taggy";
  let eqfn[taggy] eq3 = taggyeq;
  test_parameterized[taggy](eq3,
                            one(1), two(1, 2), three(1, 2, 3), two(17, 42));

  /*
   * FIXME: Segfault.  Also appears to be caused only after upcall_grow_task

  log "*** test parameterized: taggypar[int]";
  let eqfn[taggypar[int]] eq4 = taggypareq[int];
  test_parameterized[taggypar[int]](eq4,
                                    onepar[int](1),
                                    twopar[int](1, 2),
                                    threepar[int](1, 2, 3),
                                    twopar[int](17, 42));
  log "*** end test parameterized: taggypar[int]";

   */

  log "*** test parameterized: reccy";
  let reccy reccy1 = rec(x=1, y=2, t=one(1));
  let reccy reccy2 = rec(x=345, y=2, t=two(1, 2));
  let reccy reccy3 = rec(x=1, y=777, t=three(1, 2, 3));
  let reccy reccy4 = rec(x=19, y=252, t=two(17, 42));
  let eqfn[reccy] eq5 = reccyeq;
  test_parameterized[reccy](eq5,
                            reccy1, reccy2, reccy3, reccy4);
  log "*** end test parameterized: reccy";

  log "*** done";
}
<|endoftext|>


<commit_before>use state::State;
use context::BaseContext;

pub use self::handlers::ActionHandlers;

#[derive(Debug)]
pub enum Action {
    Message(self::message::Action)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::BaseContext;
    use state::State;
    use Message;

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Debug)]
    pub struct Action;

    impl Action {
        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Message::new("".to_string()))
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }
}
<commit_msg>Action: derice Clone<commit_after>use state::State;
use context::BaseContext;

pub use self::handlers::ActionHandlers;

#[derive(Clone, Debug)]
pub enum Action {
    Message(self::message::Action)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::BaseContext;
    use state::State;
    use Message;

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Clone, Debug)]
    pub struct Action;

    impl Action {
        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Message::new("".to_string()))
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }
}
<|endoftext|>