<commit_before>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::PartialEq;
use std::str::FromStr;
use std::fmt;
use std::num;

/// 2D vector in cartesian coordinates
#[derive(Debug, Clone, Copy)]
pub struct Vec2 {
    /// component of vector
    pub x: f64,
    /// component of vector
    pub y: f64,
}

impl Vec2 {
    /// Constructs a new `Vec2`.
    pub fn new<I: Into<f64>>(x: I, y: I) -> Vec2 {
        Vec2 {
            x: x.into(),
            y: y.into(),
        }
    }
    /// Constructs a new `Vec2` from polar coordinates $(r, \theta)$.
    pub fn from_polar<I: Into<f64>>(r: I, theta: I) -> Vec2 {
        let (r, theta) = (r.into(), theta.into());
        Vec2::new(r * f64::cos(theta), r * f64::sin(theta))
    }
    /// Create a zero `Vec2`
    pub fn zero() -> Vec2 {
        Vec2::new(0.0, 0.0)
    }
    /// Scalar product
    pub fn dot(self, rhs: Vec2) -> f64 {
        self.x * rhs.x + self.y * rhs.y
    }
    /// Orthogonal vector
    pub fn cross(self) -> Vec2 {
        Vec2::new(self.y, -self.x)
    }
    /// Area of parallelogramm
    pub fn area(self, rhs: Vec2) -> f64 {
        self.dot(rhs.cross())
    }
    /// Vector length
    pub fn len(self) -> f64 {
        self.dot(self).sqrt()
    }
    /// Unary vector, co-directed with given
    pub fn ort(self) -> Vec2 {
        self / self.len()
    }
    /// Squares of the vector coordinates
    pub fn sqr(self) -> Vec2 {
        self * self
    }
    /// Square root of vector coordinates
    pub fn sqrt(self) -> Vec2 {
        Vec2::new(self.x.sqrt(), self.y.sqrt())
    }
    /// Constructs dual basis for given.
    ///
    /// Dual basis $(b_1, b_2)$ for basis $(a_1, a_2)$ satisfies relation
    /// $$a_i \cdot b_j = \delta_{ij}$$
    ///
    /// # Example
    /// ```
    /// use linal::Vec2;
    ///
    /// let a1 = Vec2::new(2, 0);
    /// let a2 = Vec2::new(3, 4);
    ///
    /// let (b1, b2) = Vec2::dual_basis((a1, a2));
    /// assert_eq!(b1, Vec2::new(0.5, -0.375));
    /// assert_eq!(b2, Vec2::new(0.0, 0.25));
    /// ```
    pub fn dual_basis(basis: (Vec2, Vec2)) -> (Vec2, Vec2) {
        let (a, b) = basis;

        // At first, construct vectors a1 and b1 such that
        // a1.dot(b) = 0 и b1.dot(a) = 0
        let a1 = a - b * a.dot(b) / b.dot(b);
        let b1 = b - a * b.dot(a) / a.dot(a);

        // And second, normalize them
        let a2 = a1 / a.dot(a1);
        let b2 = b1 / b.dot(b1);

        (a2, b2)
    }
}

impl Add for Vec2 {
    type Output = Self;

    fn add(self, _rhs: Self) -> Self {
        Vec2::new(self.x + _rhs.x, self.y + _rhs.y)
    }
}

impl Sub for Vec2 {
    type Output = Self;

    fn sub(self, _rhs: Self) -> Self {
        Vec2::new(self.x - _rhs.x, self.y - _rhs.y)
    }
}

impl Mul for Vec2 {
    type Output = Self;

    fn mul(self, _rhs: Vec2) -> Vec2 {
        Vec2::new(self.x * _rhs.x, self.y * _rhs.y)
    }
}

impl<I: Into<f64>> Mul<I> for Vec2 {
    type Output = Self;

    fn mul(self, _rhs: I) -> Vec2 {
        let _rhs = _rhs.into();
        Vec2::new(self.x * _rhs, self.y * _rhs)
    }
}

impl<I: Into<f64>> Div<I> for Vec2 {
    type Output = Self;

    fn div(self, _rhs: I) -> Vec2 {
        let _rhs = _rhs.into();
        if _rhs == 0.0 {
            panic!("Can't divide by zero!");
        }
        Vec2::new(self.x / _rhs, self.y / _rhs)
    }
}

impl Neg for Vec2 {
    type Output = Self;

    fn neg(self) -> Self {
        Self::new(-self.x, -self.y)
    }
}

impl PartialEq for Vec2 {
    fn eq(&self, other: &Self) -> bool {
        self.x == other.x && self.y == other.y
    }
}

impl fmt::Display for Vec2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.x, self.y)
    }
}

impl FromStr for Vec2 {
    type Err = num::ParseFloatError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let words: Vec<&str> = s.split_whitespace().collect();
        let x: f64 = try!(words[0].parse());
        let y: f64 = try!(words[1].parse());
        Ok(Self::new(x, y))
    }
}

#[cfg(test)]
mod linal_test {
    use super::*;

    #[test]
    fn vec2_mul() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(3, 6);
        let r = a * 3;
        assert_eq!(r, b);
    }

    #[test]
    #[should_panic]
    fn vec2_div() {
        let a = Vec2::new(1, 2);
        let _ = a / 0.0;
    }

    #[test]
    fn vec2_from_polar() {
        let a = Vec2::new(3, 4);
        let b = Vec2::from_polar(5.0, f64::atan2(4.0, 3.0));
        assert!((a - b).len() < 1e-10);
    }

    #[test]
    fn vec2_add() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = Vec2::new(-2, 8);
        assert_eq!(a + b, c);
    }

    #[test]
    fn vec2_sub() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = Vec2::new(4, -4);
        assert_eq!(a - b, c);
    }

    #[test]
    fn vec2_dot() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = 9.0;
        assert_eq!(a.dot(b), c);
        assert_eq!(b.dot(a), c);
    }

    #[test]
    fn vec2_area() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = 12.0;
        assert_eq!(a.area(b), c);
        assert_eq!(b.area(a), -c);
    }

    #[test]
    fn vec2_cross_z() {
        let a = Vec2::new(1, 2);
        let b = 2.0;
        let c = Vec2::new(4, -2);
        assert_eq!(a.cross() * b, c);
    }

    #[test]
    fn vec2_neg() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-1, -2);
        assert_eq!(-a, b);
    }

    #[test]
    fn vec2_parse() {
        let a: Vec2 = "1 2".parse().unwrap();
        assert_eq!(a, Vec2::new(1, 2));
    }
}
<commit_msg>[upd] Vec2 dual_basis using cross<commit_after>use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::PartialEq;
use std::str::FromStr;
use std::fmt;
use std::num;

/// 2D vector in cartesian coordinates
#[derive(Debug, Clone, Copy)]
pub struct Vec2 {
    /// component of vector
    pub x: f64,
    /// component of vector
    pub y: f64,
}

impl Vec2 {
    /// Constructs a new `Vec2`.
    pub fn new<I: Into<f64>>(x: I, y: I) -> Vec2 {
        Vec2 {
            x: x.into(),
            y: y.into(),
        }
    }
    /// Constructs a new `Vec2` from polar coordinates $(r, \theta)$.
    pub fn from_polar<I: Into<f64>>(r: I, theta: I) -> Vec2 {
        let (r, theta) = (r.into(), theta.into());
        Vec2::new(r * f64::cos(theta), r * f64::sin(theta))
    }
    /// Create a zero `Vec2`
    pub fn zero() -> Vec2 {
        Vec2::new(0.0, 0.0)
    }
    /// Scalar product
    pub fn dot(self, rhs: Vec2) -> f64 {
        self.x * rhs.x + self.y * rhs.y
    }
    /// Orthogonal vector
    pub fn cross(self) -> Vec2 {
        Vec2::new(self.y, -self.x)
    }
    /// Area of parallelogramm
    pub fn area(self, rhs: Vec2) -> f64 {
        self.dot(rhs.cross())
    }
    /// Vector length
    pub fn len(self) -> f64 {
        self.dot(self).sqrt()
    }
    /// Unary vector, co-directed with given
    pub fn ort(self) -> Vec2 {
        self / self.len()
    }
    /// Squares of the vector coordinates
    pub fn sqr(self) -> Vec2 {
        self * self
    }
    /// Square root of vector coordinates
    pub fn sqrt(self) -> Vec2 {
        Vec2::new(self.x.sqrt(), self.y.sqrt())
    }
    /// Constructs dual basis for given.
    ///
    /// Dual basis $(\vec{b}_1, \vec{b}_2)$ for basis $(\vec{a}_1, \vec{a}_2)$ satisfies relation
    /// $$\vec{a}_i \cdot \vec{b}_j = \delta_{ij}$$
    ///
    /// # Example
    /// ```
    /// use linal::Vec2;
    ///
    /// let a1 = Vec2::new(2, 0);
    /// let a2 = Vec2::new(3, 4);
    ///
    /// let (b1, b2) = Vec2::dual_basis((a1, a2));
    /// assert_eq!(b1, Vec2::new(0.5, -0.375));
    /// assert_eq!(b2, Vec2::new(0.0, 0.25));
    /// ```
    pub fn dual_basis(basis: (Vec2, Vec2)) -> (Vec2, Vec2) {
        let (a, b) = basis;
        let area = a.area(b);
        (b.cross() / area, -a.cross() / area)
    }
}

impl Add for Vec2 {
    type Output = Self;

    fn add(self, _rhs: Self) -> Self {
        Vec2::new(self.x + _rhs.x, self.y + _rhs.y)
    }
}

impl Sub for Vec2 {
    type Output = Self;

    fn sub(self, _rhs: Self) -> Self {
        Vec2::new(self.x - _rhs.x, self.y - _rhs.y)
    }
}

impl Mul for Vec2 {
    type Output = Self;

    fn mul(self, _rhs: Vec2) -> Vec2 {
        Vec2::new(self.x * _rhs.x, self.y * _rhs.y)
    }
}

impl<I: Into<f64>> Mul<I> for Vec2 {
    type Output = Self;

    fn mul(self, _rhs: I) -> Vec2 {
        let _rhs = _rhs.into();
        Vec2::new(self.x * _rhs, self.y * _rhs)
    }
}

impl<I: Into<f64>> Div<I> for Vec2 {
    type Output = Self;

    fn div(self, _rhs: I) -> Vec2 {
        let _rhs = _rhs.into();
        if _rhs == 0.0 {
            panic!("Can't divide by zero!");
        }
        Vec2::new(self.x / _rhs, self.y / _rhs)
    }
}

impl Neg for Vec2 {
    type Output = Self;

    fn neg(self) -> Self {
        Self::new(-self.x, -self.y)
    }
}

impl PartialEq for Vec2 {
    fn eq(&self, other: &Self) -> bool {
        self.x == other.x && self.y == other.y
    }
}

impl fmt::Display for Vec2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.x, self.y)
    }
}

impl FromStr for Vec2 {
    type Err = num::ParseFloatError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let words: Vec<&str> = s.split_whitespace().collect();
        let x: f64 = try!(words[0].parse());
        let y: f64 = try!(words[1].parse());
        Ok(Self::new(x, y))
    }
}

#[cfg(test)]
mod linal_test {
    use super::*;

    #[test]
    fn vec2_mul() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(3, 6);
        let r = a * 3;
        assert_eq!(r, b);
    }

    #[test]
    #[should_panic]
    fn vec2_div() {
        let a = Vec2::new(1, 2);
        let _ = a / 0.0;
    }

    #[test]
    fn vec2_from_polar() {
        let a = Vec2::new(3, 4);
        let b = Vec2::from_polar(5.0, f64::atan2(4.0, 3.0));
        assert!((a - b).len() < 1e-10);
    }

    #[test]
    fn vec2_add() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = Vec2::new(-2, 8);
        assert_eq!(a + b, c);
    }

    #[test]
    fn vec2_sub() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = Vec2::new(4, -4);
        assert_eq!(a - b, c);
    }

    #[test]
    fn vec2_dot() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = 9.0;
        assert_eq!(a.dot(b), c);
        assert_eq!(b.dot(a), c);
    }

    #[test]
    fn vec2_area() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-3, 6);
        let c = 12.0;
        assert_eq!(a.area(b), c);
        assert_eq!(b.area(a), -c);
    }

    #[test]
    fn vec2_cross_z() {
        let a = Vec2::new(1, 2);
        let b = 2.0;
        let c = Vec2::new(4, -2);
        assert_eq!(a.cross() * b, c);
    }

    #[test]
    fn vec2_neg() {
        let a = Vec2::new(1, 2);
        let b = Vec2::new(-1, -2);
        assert_eq!(-a, b);
    }

    #[test]
    fn vec2_parse() {
        let a: Vec2 = "1 2".parse().unwrap();
        assert_eq!(a, Vec2::new(1, 2));
    }
}
<|endoftext|>


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

use crate::types::*;

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        let oninput = self
            .link
            .callback(move |e: InputData| Msg::SetCommand(e.value));
        let onkeypress = self
            .link
            .callback(move |e: KeyboardEvent| Msg::CommandKey(e));

        let mut command_class = vec![
            "focus:border-blue-500",
            "focus:ring-1",
            "focus:ring-blue-500",
            "focus:outline-none",
            "text-sm",
            "text-black",
            "placeholder-gray-500",
            "border",
            "border-gray-200",
            "rounded-md",
            "py-2",
            "pl-10",
        ];

        if self.parsed_command.is_some() {
            command_class.push("bg-green-500")
        } else {
            command_class.push("bg-red-500")
        }

        html! {

            <input
              class=command_class
              oninput=oninput
              onkeydown=onkeypress
              value=self.command
            ></input>
            { for actions }

        }
    }

    fn is_valid_value(&self, new_value: &Value) -> bool {
        match self.cursor.back() {
            Some(selector) => {
                let parent = self.lookup(&self.parent_ref().unwrap()).unwrap();
                match &parent.value {
                    Value::Inner(v) => {
                        let field = &RUST_SCHEMA
                            .kinds
                            .iter()
                            .find(|k| k.name == v.kind)
                            .unwrap()
                            .fields
                            .iter()
                            .find(|f| f.name == selector.field)
                            .unwrap();
                        match field.type_ {
                            Type::String => {
                                if let Value::String(_) = new_value {
                                    (field.validator)(new_value)
                                } else {
                                    false
                                }
                            }
                            Type::Bool => {
                                if let Value::Bool(_) = new_value {
                                    true
                                } else {
                                    false
                                }
                            }
                            Type::Ref => true,
                        }
                    }
                    _ => true,
                }
            }
            None => true,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { &action.text }
            </button>
        }
    }

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

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(kind: &str) -> &[Field] {
        match RUST_SCHEMA.kinds.iter().find(|k| k.name == kind) {
            Some(kind) => kind.fields,
            None => &[],
        }
    }

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

    fn view_node_list(&self, references: &[Ref], path: &Path) -> Vec {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let mut nodes = references
            .iter()
            .enumerate()
            .map(|(i, n)| {
                let mut path = path.clone();
                let l = path.len();
                path[l - 1].index = Some(i);
                self.view_node(n, &path)
            })
            .collect::<Vec<_>>();
        let path = path.clone();
        let callback = self
            .link
            .callback(move |_: MouseEvent| Msg::Select(path.clone()));
        let head = html! {

{ "▷" }

        };
        nodes.insert(0, head);
        nodes
    }

    // fn view_node(&self, reference: &Ref, path: Path, cursor: Option<Path>) -> Html {
    fn view_node(&self, reference: &Ref, path: &Path) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let path_clone = path.clone();
        let callback = self
            .link
            .callback(move |_: MouseEvent| Msg::Select(path_clone.clone()));
        let value = if reference == INVALID_REF {
            html! {
                { "◆" }
            }
        } else {
            match self.lookup(reference) {
                Some(node) => self.view_value(&node.reference, &node.value, &path),
                None => {
                    html! {
                        { format!("invalid: {}", reference) }
                    }
                }
            }
        };
        html! {

                { value }

        }
    }

    fn view_child(&self, value: &Inner, field_name: &str, path: &Path) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: Some(0),
            },
        );
        match value.children.get(field_name).and_then(|v| v.get(0)) {
            Some(n) => self.view_node(n, &path),
            // Empty list vs hole vs special value?
            // TODO: How to traverse nested lists in preorder?
            None => self.view_node(&"-".to_string(), &path),
            // None => self.view_node_list(&[], &path),
        }
    }

    fn view_children(&self, value: &Inner, field_name: &str, path: &Path) -> Vec {
        let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = value.children.get(field_name).unwrap_or(&empty);
        self.view_node_list(&children, &path)
    }

    fn view_value(&self, reference: &Ref, value: &Value, path: &Path) -> Html {
        match value {
            Value::Hole => {
                html! { { "◆" } }
            }
            Value::Bool(v) => {
                let v = if *v { "true" } else { "false" };
                html! { { v } }
            }
            Value::Int(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::Float(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::String(v) => {
                html! { { v } }
            }
            Value::Inner(v) => match v.kind.as_ref() {
                "document" => {
                    let bindings = self
                        .view_children(&v, "bindings", &path)
                        .into_iter()
                        .map(|b| {
                            html! {

{ b }

                            }
                        });
                    html! {

                        { for bindings }

                    }
                }
                "ref" => {
                    let target = self.view_child(&v, "target", &path);
                    html! {

                        { target }

                    }
                }
                "binary_operator" => {
                    let operator = self.view_child(&v, "operator", &path);
                    let left = self.view_child(&v, "left", &path);
                    let right = self.view_child(&v, "right", &path);
                    html! {

                        { left }
                        { operator }
                        { right }

                    }
                }
                "accessor" => {
                    let object = self.view_child(&v, "object", &path);
                    let field = self.view_child(&v, "field", &path);
                    html! {

                        { object }
                        { "." }
                        { field }

                    }
                }
                "binding" => {
                    let name = self.view_child(&v, "name", &path);
                    let value = self.view_child(&v, "value", &path);
                    html! {
                        { "let" }{ name }{ "=" }{ value }
                    }
                }
                "qualify" => {
                    let parent = self.view_child(&v, "parent", &path);
                    let child = self.view_child(&v, "child", &path);
                    html! {
                        { parent }{ "::" }{ child }
                    }
                }
                "if" => {
                    let condition = self.view_child(&v, "condition", &path);
                    let true_body = self.view_child(&v, "true_body", &path);
                    let false_body = self.view_child(&v, "false_body", &path);
                    html! {

                                { "if" }{ condition }{ "{" }

                                { true_body }

                                { "}" }{ "else" }{ "{" }

                                { false_body }

                                { "}" }

                    }
                }
                "function_definition" => {
                    let label = self.view_child(&v, "name", &path);
                    let args = self.view_children(&v, "arguments", &path);
                    let body = self.view_child(&v, "body", &path);
                    let return_type = self.view_child(&v, "return_type", &path);
                    // let async_ = self.view_child(&v, "async", &path);
                    // let pub_ = self.view_child(&v, "pub", &path);

                    html! {

{ "#" }

                            // { pub_ }

{ "fn" }{ label }{ "(" }{ for args }{ ")" }{ "->" }{ return_type }{ "{" }

{ body }
{ "}" }

                    }
                }
                "struct" => {
                    let label = self.view_child(&v, "name", &path);
                    let fields = self
                        .view_children(&v, "fields", &path)
                        .into_iter()
                        .map(|v| {
                            html! {

{ v }{ "," }

                            }
                        });

                    html! {

                        { "struct" }{ label }
                        { "{" }{ for fields }{ "}" }

                    }
                }
                "string" => {
                    let value = self.view_child(&v, "value", &path);

                    html! {

                        { "\"" }{ value }{ "\"" }

                    }
                }
                "enum" => {
                    let label = self.view_child(&v, "name", &path);
                    let variants = self
                        .view_children(&v, "variants", &path)
                        .into_iter()
                        .map(|v| {
                            html! {

{ v }{ "," }

                            }
                        });

                    html! {

                        { "enum" }{ label }
                        { "{" }{ for variants }{ "}" }

                    }
                }
                "pattern" => {
                    let name = self.lookup(&v.children["name"][0]).unwrap();
                    let name = match &name.value {
                        Value::String(v) => v.clone(),
                        _ => "error".to_string(),
                    };
                    html! {

                        { name }

                    }
                }
                "function_call" => {
                    let function = self.view_child(&v, "function", path);
                    // let function_name = self.view_children(&v, "function");
                    // let function_name = "xxx";
                    // .and_then(|n| n.label())
                    // .map(|l| l.name.clone())
                    // .unwrap_or("<UNKNOWN>".to_string());
                    let args = self.view_children(&v, "arguments", path);
                    html! {

                        { function }
                        { "(" }{ for args }{ ")" }

                    }
                }
                kind => {
                    html! { { kind } }
                }
            },
        }
    }
}
<commit_msg>arguments<commit_after>use yew::prelude::*;

use crate::types::*;

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        let oninput = self
            .link
            .callback(move |e: InputData| Msg::SetCommand(e.value));
        let onkeypress = self
            .link
            .callback(move |e: KeyboardEvent| Msg::CommandKey(e));

        let mut command_class = vec![
            "focus:border-blue-500",
            "focus:ring-1",
            "focus:ring-blue-500",
            "focus:outline-none",
            "text-sm",
            "text-black",
            "placeholder-gray-500",
            "border",
            "border-gray-200",
            "rounded-md",
            "py-2",
            "pl-10",
        ];

        if self.parsed_command.is_some() {
            command_class.push("bg-green-500")
        } else {
            command_class.push("bg-red-500")
        }

        html! {

            <input
              class=command_class
              oninput=oninput
              onkeydown=onkeypress
              value=self.command
            ></input>
            { for actions }

        }
    }

    fn is_valid_value(&self, new_value: &Value) -> bool {
        match self.cursor.back() {
            Some(selector) => {
                let parent = self.lookup(&self.parent_ref().unwrap()).unwrap();
                match &parent.value {
                    Value::Inner(v) => {
                        let field = &RUST_SCHEMA
                            .kinds
                            .iter()
                            .find(|k| k.name == v.kind)
                            .unwrap()
                            .fields
                            .iter()
                            .find(|f| f.name == selector.field)
                            .unwrap();
                        match field.type_ {
                            Type::String => {
                                if let Value::String(_) = new_value {
                                    (field.validator)(new_value)
                                } else {
                                    false
                                }
                            }
                            Type::Bool => {
                                if let Value::Bool(_) = new_value {
                                    true
                                } else {
                                    false
                                }
                            }
                            Type::Ref => true,
                        }
                    }
                    _ => true,
                }
            }
            None => true,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { &action.text }
            </button>
        }
    }

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

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(kind: &str) -> &[Field] {
        match RUST_SCHEMA.kinds.iter().find(|k| k.name == kind) {
            Some(kind) => kind.fields,
            None => &[],
        }
    }

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

    fn view_node_list(&self, references: &[Ref], path: &Path) -> Vec {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let mut nodes = references
            .iter()
            .enumerate()
            .map(|(i, n)| {
                let mut path = path.clone();
                let l = path.len();
                path[l - 1].index = Some(i);
                self.view_node(n, &path)
            })
            .collect::<Vec<_>>();
        let path = path.clone();
        let callback = self
            .link
            .callback(move |_: MouseEvent| Msg::Select(path.clone()));
        let head = html! {

{ "▷" }

        };
        nodes.insert(0, head);
        nodes
    }

    // fn view_node(&self, reference: &Ref, path: Path, cursor: Option<Path>) -> Html {
    fn view_node(&self, reference: &Ref, path: &Path) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let path_clone = path.clone();
        let callback = self
            .link
            .callback(move |_: MouseEvent| Msg::Select(path_clone.clone()));
        let value = if reference == INVALID_REF {
            html! {
                { "◆" }
            }
        } else {
            match self.lookup(reference) {
                Some(node) => self.view_value(&node.reference, &node.value, &path),
                None => {
                    html! {
                        { format!("invalid: {}", reference) }
                    }
                }
            }
        };
        html! {

                { value }

        }
    }

    fn view_child(&self, value: &Inner, field_name: &str, path: &Path) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: Some(0),
            },
        );
        match value.children.get(field_name).and_then(|v| v.get(0)) {
            Some(n) => self.view_node(n, &path),
            // Empty list vs hole vs special value?
            // TODO: How to traverse nested lists in preorder?
            None => self.view_node(&"-".to_string(), &path),
            // None => self.view_node_list(&[], &path),
        }
    }

    fn view_children(&self, value: &Inner, field_name: &str, path: &Path) -> Vec {
        let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = value.children.get(field_name).unwrap_or(&empty);
        self.view_node_list(&children, &path)
    }

    fn view_value(&self, reference: &Ref, value: &Value, path: &Path) -> Html {
        match value {
            Value::Hole => {
                html! { { "◆" } }
            }
            Value::Bool(v) => {
                let v = if *v { "true" } else { "false" };
                html! { { v } }
            }
            Value::Int(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::Float(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::String(v) => {
                html! { { v } }
            }
            Value::Inner(v) => match v.kind.as_ref() {
                "document" => {
                    let bindings = self
                        .view_children(&v, "bindings", &path)
                        .into_iter()
                        .map(|b| {
                            html! {

{ b }

                            }
                        });
                    html! {

                        { for bindings }

                    }
                }
                "ref" => {
                    let target = self.view_child(&v, "target", &path);
                    html! {

                        { target }

                    }
                }
                "binary_operator" => {
                    let operator = self.view_child(&v, "operator", &path);
                    let left = self.view_child(&v, "left", &path);
                    let right = self.view_child(&v, "right", &path);
                    html! {

                        { left }
                        { operator }
                        { right }

                    }
                }
                "accessor" => {
                    let object = self.view_child(&v, "object", &path);
                    let field = self.view_child(&v, "field", &path);
                    html! {

                        { object }
                        { "." }
                        { field }

                    }
                }
                "binding" => {
                    let name = self.view_child(&v, "name", &path);
                    let value = self.view_child(&v, "value", &path);
                    html! {
                        { "let" }{ name }{ "=" }{ value }
                    }
                }
                "qualify" => {
                    let parent = self.view_child(&v, "parent", &path);
                    let child = self.view_child(&v, "child", &path);
                    html! {
                        { parent }{ "::" }{ child }
                    }
                }
                "if" => {
                    let condition = self.view_child(&v, "condition", &path);
                    let true_body = self.view_child(&v, "true_body", &path);
                    let false_body = self.view_child(&v, "false_body", &path);
                    html! {

                                { "if" }{ condition }{ "{" }

                                { true_body }

                                { "}" }{ "else" }{ "{" }

                                { false_body }

                                { "}" }

                    }
                }
                "function_definition" => {
                    let label = self.view_child(&v, "name", &path);
                    let args = self
                        .view_children(&v, "arguments", &path)
                        .into_iter()
                        .enumerate()
                        .map(|(i, v)| {
                            if i == 0 || i == 1 {
                                v
                            } else {
                                html! {
                                    { "," }{ v }
                                }
                            }
                        });
                    let body = self.view_child(&v, "body", &path);
                    let return_type = self.view_child(&v, "return_type", &path);
                    // let async_ = self.view_child(&v, "async", &path);
                    // let pub_ = self.view_child(&v, "pub", &path);

                    html! {

{ "#" }

                            // { pub_ }

{ "fn" }{ label }{ "(" }{ for args }{ ")" }{ "->" }{ return_type }{ "{" }

{ body }
{ "}" }

                    }
                }
                "struct" => {
                    let label = self.view_child(&v, "name", &path);
                    let fields = self
                        .view_children(&v, "fields", &path)
                        .into_iter()
                        .map(|v| {
                            html! {

{ v }{ "," }

                            }
                        });

                    html! {

                        { "struct" }{ label }
                        { "{" }{ for fields }{ "}" }

                    }
                }
                "string" => {
                    let value = self.view_child(&v, "value", &path);

                    html! {

                        { "\"" }{ value }{ "\"" }

                    }
                }
                "enum" => {
                    let label = self.view_child(&v, "name", &path);
                    let variants = self
                        .view_children(&v, "variants", &path)
                        .into_iter()
                        .map(|v| {
                            html! {

{ v }{ "," }

                            }
                        });

                    html! {

                        { "enum" }{ label }
                        { "{" }{ for variants }{ "}" }

                    }
                }
                "pattern" => {
                    let name = self.lookup(&v.children["name"][0]).unwrap();
                    let name = match &name.value {
                        Value::String(v) => v.clone(),
                        _ => "error".to_string(),
                    };
                    html! {

                        { name }

                    }
                }
                "function_call" => {
                    let function = self.view_child(&v, "function", path);
                    // let function_name = self.view_children(&v, "function");
                    // let function_name = "xxx";
                    // .and_then(|n| n.label())
                    // .map(|l| l.name.clone())
                    // .unwrap_or("<UNKNOWN>".to_string());
                    let args = self
                        .view_children(&v, "arguments", path)
                        .into_iter()
                        .enumerate()
                        .map(|(i, v)| {
                            if i == 0 || i == 1 {
                                v
                            } else {
                                html! {
                                    { "," }{ v }
                                }
                            }
                        });
                    html! {

                        { function }
                        { "(" }{ for args }{ ")" }

                    }
                }
                kind => {
                    html! { { kind } }
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>use native;
use std::comm::channel;

struct WorkUnit {
    arg: int,
    callback: Sender<int>,
}

enum MessageToWorker {
    Work(WorkUnit),
    Halt,
}

enum MessageToDispatcher {
    Dispatch(WorkUnit),
    HaltAll,
}

struct WorkQueue {
    dispatcher: Sender<MessageToDispatcher>,
}

impl WorkQueue {
    pub fn create(worker_count: int) -> WorkQueue {
        let (want_work, idle_worker) = channel::<Sender<MessageToWorker>>();
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher>();

        // dispatcher
        native::task::spawn(proc() {
            let mut worker_count = worker_count;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });

        for _ in range(0, worker_count) {
            // worker
            let want_work_copy = want_work.clone();
            native::task::spawn(proc() {
                let want_work = want_work_copy;
                loop {
                    let (reply_with_work, get_work_unit) = channel::<MessageToWorker>();
                    want_work.send(reply_with_work);
                    let work_unit = match get_work_unit.recv() {
                        Work(wu) => wu,
                        Halt     => return
                    };
                    let rv = work_unit.arg * 2;
                    work_unit.callback.send(rv);
                }
            });
        }

        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn execute(&self, arg: int) -> Receiver<int> {
        let (reply_with_rv, wait_for_rv) = channel::<int>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, callback: reply_with_rv}));
        return wait_for_rv;
    }
}

impl Drop for WorkQueue {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

#[test]
fn test_queue() {
    let queue = WorkQueue::create(3);
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<commit_msg>register worker with dispatcher<commit_after>use native;
use std::comm::channel;

struct WorkUnit {
    arg: int,
    callback: Sender<int>,
}

enum MessageToWorker {
    Work(WorkUnit),
    Halt,
}

enum MessageToDispatcher {
    Dispatch(WorkUnit),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker>>>),
}

struct WorkQueue {
    dispatcher: Sender<MessageToDispatcher>,
}

impl WorkQueue {
    pub fn create(worker_count: int) -> WorkQueue {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher>();

        // dispatcher
        native::task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });

        for _ in range(0, worker_count) {
            // worker
            let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker>>>();
            dispatcher.send(RegisterWorker(reg_s));
            let want_work = reg_r.recv();

            native::task::spawn(proc() {
                let want_work = want_work;
                loop {
                    let (reply_with_work, get_work_unit) = channel::<MessageToWorker>();
                    want_work.send(reply_with_work);
                    let work_unit = match get_work_unit.recv() {
                        Work(wu) => wu,
                        Halt     => return
                    };
                    let rv = work_unit.arg * 2;
                    work_unit.callback.send(rv);
                }
            });
        }

        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn execute(&self, arg: int) -> Receiver<int> {
        let (reply_with_rv, wait_for_rv) = channel::<int>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, callback: reply_with_rv}));
        return wait_for_rv;
    }
}

impl Drop for WorkQueue {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

#[test]
fn test_queue() {
    let queue = WorkQueue::create(3);
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<|endoftext|>


<commit_before>//! Exposes the JavaScript event loop for scheduling asynchronous events.
//!
//! ## The Event Loop
//!
//! The [_event loop_][event-loop] is how Node.js provides JavaScript programs
//! access to concurrent events such as completion of [file][fs] or
//! [network][net] operations, notification of scheduled [timers][timer], or
//! receiving of messages from other [processes][process].
//!
//! When an asynchronous operation is started from JavaScript, it registers
//! a JavaScript callback function to wait for the operation to complete. When
//! the operation completes, the callback and the result data are added to an
//! internal _event queue_ in the Node.js runtime so that the event can be
//! processed in order.
//!
//! The event loop processes completed events one at a time in the JavaScript
//! execution thread by calling the registered callback function with its result
//! value as an argument.
//!
//! ## Creating Custom Events
//!
//! This module allows Neon programs to create new types of concurrent events
//! in Rust and expose them to JavaScript as asynchronous functions.
//!
//! A common use for custom events is to run expensive or long-lived
//! computations in a background thread without blocking the JavaScript
//! thread. For example, using the [`psd` crate][psd-crate], a Neon program could
//! asynchronously parse (potentially large) [PSD files][psd-file] in a
//! background thread:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! #
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
//! #
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//!     // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
//!     // sent across threads.
//!     let filename = cx.argument::<JsString>(0)?.value(&mut cx);
//!     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
//!     let queue = cx.queue();
//!
//!     // Spawn a thread to complete the execution. This will _not_ block the
//!     // JavaScript event loop.
//!     std::thread::spawn(move || {
//!         // Do the heavy lifting inside the background thread.
//!         parse(filename, callback, queue);
//!     });
//!
//!     Ok(cx.undefined())
//! }
//! # }
//! ```
//!
//! (Note that this usage of [`spawn`](std::thread::spawn) makes use of Rust's
//! [`move`][move] syntax to transfer ownership of data to the background
//! thread.)
//!
//! Upon completion of its task, the background thread can use the JavaScript
//! callback and the event queue to notify the main thread of the result:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! # use psd::Psd;
//! # use failure::Error;
//! #
//! fn psd_from_filename(filename: String) -> Result<Psd, Error> {
//!     Psd::from_bytes(&std::fs::read(&filename)?)
//! }
//!
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
//!     let result = psd_from_filename(filename);
//!
//!     // Send a closure as a task to be executed by the JavaScript event
//!     // queue. This _will_ block the event queue while executing.
//!     queue.send(move |mut cx| {
//!         let callback = callback.into_inner(&mut cx);
//!         let this = cx.undefined();
//!         let null = cx.null();
//!         let args = match result {
//!             Ok(psd) => {
//!                 // Extract data from the parsed file.
//!                 let width = cx.number(psd.width());
//!                 let height = cx.number(psd.height());
//!
//!                 // Save the data in a result object.
//!                 let obj = cx.empty_object();
//!                 obj.set(&mut cx, "width", width)?;
//!                 obj.set(&mut cx, "height", height)?;
//!                 vec![
//!                     cx.null().upcast::<JsValue>(),
//!                     obj.upcast(),
//!                 ]
//!             }
//!             Err(_) => {
//!                 // A full implementation would provide
//!                 // more detailed error diagnostics.
//!                 let err = cx.string("PSD parse error");
//!                 vec![
//!                     err.upcast::<JsValue>(),
//!                 ]
//!             }
//!         };
//!
//!         callback.call(&mut cx, this, args)?;
//!
//!         Ok(())
//!     });
//! }
//! # }
//! ```
//!
//! ## See also
//!
//! 1. Panu Pitkamaki. [Event loop from 10,000ft][event-loop].
//!
//! [event-loop]: https://bytearcher.com/articles/event-loop-10-000ft/
//! [fs]: https://nodejs.org/dist/latest/docs/api/fs.html
//! [net]: https://nodejs.org/dist/latest/docs/api/net.html
//! [process]: https://nodejs.org/dist/latest/docs/api/process.html
//! [timer]: https://nodejs.org/dist/latest/docs/api/timers.html
//! [move]: https://doc.rust-lang.org/std/keyword.move.html
//! [psd-crate]: https://crates.io/crates/psd
//! [psd-file]: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
mod event_queue;

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
pub use self::event_queue::{EventQueue, EventQueueError};

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
mod event_handler;

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
pub use self::event_handler::EventHandler;

#[cfg(all(feature = "napi-1", feature = "event-handler-api"))]
compile_error!(
    "The `EventHandler` API is not supported with the N-API \
    backend. Use `EventQueue` instead."
);
<commit_msg>Use error message from PSD error on failure.<commit_after>//! Exposes the JavaScript event loop for scheduling asynchronous events.
//!
//! ## The Event Loop
//!
//! The [_event loop_][event-loop] is how Node.js provides JavaScript programs
//! access to concurrent events such as completion of [file][fs] or
//! [network][net] operations, notification of scheduled [timers][timer], or
//! receiving of messages from other [processes][process].
//!
//! When an asynchronous operation is started from JavaScript, it registers
//! a JavaScript callback function to wait for the operation to complete. When
//! the operation completes, the callback and the result data are added to an
//! internal _event queue_ in the Node.js runtime so that the event can be
//! processed in order.
//!
//! The event loop processes completed events one at a time in the JavaScript
//! execution thread by calling the registered callback function with its result
//! value as an argument.
//!
//! ## Creating Custom Events
//!
//! This module allows Neon programs to create new types of concurrent events
//! in Rust and expose them to JavaScript as asynchronous functions.
//!
//! A common use for custom events is to run expensive or long-lived
//! computations in a background thread without blocking the JavaScript
//! thread. For example, using the [`psd` crate][psd-crate], a Neon program could
//! asynchronously parse (potentially large) [PSD files][psd-file] in a
//! background thread:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! #
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
//! #
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//!     // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
//!     // sent across threads.
//!     let filename = cx.argument::<JsString>(0)?.value(&mut cx);
//!     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
//!     let queue = cx.queue();
//!
//!     // Spawn a thread to complete the execution. This will _not_ block the
//!     // JavaScript event loop.
//!     std::thread::spawn(move || {
//!         // Do the heavy lifting inside the background thread.
//!         parse(filename, callback, queue);
//!     });
//!
//!     Ok(cx.undefined())
//! }
//! # }
//! ```
//!
//! (Note that this usage of [`spawn`](std::thread::spawn) makes use of Rust's
//! [`move`][move] syntax to transfer ownership of data to the background
//! thread.)
//!
//! Upon completion of its task, the background thread can use the JavaScript
//! callback and the event queue to notify the main thread of the result:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! # use psd::Psd;
//! # use failure::Error;
//! #
//! fn psd_from_filename(filename: String) -> Result<Psd, Error> {
//!     Psd::from_bytes(&std::fs::read(&filename)?)
//! }
//!
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
//!     let result = psd_from_filename(filename);
//!
//!     // Send a closure as a task to be executed by the JavaScript event
//!     // queue. This _will_ block the event queue while executing.
//!     queue.send(move |mut cx| {
//!         let callback = callback.into_inner(&mut cx);
//!         let this = cx.undefined();
//!         let null = cx.null();
//!         let args = match result {
//!             Ok(psd) => {
//!                 // Extract data from the parsed file.
//!                 let width = cx.number(psd.width());
//!                 let height = cx.number(psd.height());
//!
//!                 // Save the data in a result object.
//!                 let obj = cx.empty_object();
//!                 obj.set(&mut cx, "width", width)?;
//!                 obj.set(&mut cx, "height", height)?;
//!                 vec![
//!                     cx.null().upcast::<JsValue>(),
//!                     obj.upcast(),
//!                 ]
//!             }
//!             Err(err) => {
//!                 let err = cx.string(err.to_string());
//!                 vec![
//!                     err.upcast::<JsValue>(),
//!                 ]
//!             }
//!         };
//!
//!         callback.call(&mut cx, this, args)?;
//!
//!         Ok(())
//!     });
//! }
//! # }
//! ```
//!
//! ## See also
//!
//! 1. Panu Pitkamaki. [Event loop from 10,000ft][event-loop].
//!
//! [event-loop]: https://bytearcher.com/articles/event-loop-10-000ft/
//! [fs]: https://nodejs.org/dist/latest/docs/api/fs.html
//! [net]: https://nodejs.org/dist/latest/docs/api/net.html
//! [process]: https://nodejs.org/dist/latest/docs/api/process.html
//! [timer]: https://nodejs.org/dist/latest/docs/api/timers.html
//! [move]: https://doc.rust-lang.org/std/keyword.move.html
//! [psd-crate]: https://crates.io/crates/psd
//! [psd-file]: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
mod event_queue;

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
pub use self::event_queue::{EventQueue, EventQueueError};

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
mod event_handler;

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
pub use self::event_handler::EventHandler;

#[cfg(all(feature = "napi-1", feature = "event-handler-api"))]
compile_error!(
    "The `EventHandler` API is not supported with the N-API \
    backend. Use `EventQueue` instead."
);
<|endoftext|>


<commit_before>//! Wrapper types for the values returned from `File`s.
//!
//! The methods of `File` that return information about the entry on the
//! filesystem -- size, modification date, block count, or Git status -- used
//! to just return these as formatted strings, but this became inflexible once
//! customisable output styles landed.
//!
//! Instead, they will return a wrapper type from this module, which tags the
//! type with what field it is while containing the actual raw value.
//!
//! The `output::details` module, among others, uses these types to render and
//! display the information as formatted strings.

// C-style `blkcnt_t` types don’t follow Rust’s rules!
#![allow(non_camel_case_types)]
#![allow(clippy::struct_excessive_bools)]

/// The type of a file’s block count.
pub type blkcnt_t = u64;

/// The type of a file’s group ID.
pub type gid_t = u32;

/// The type of a file’s inode.
pub type ino_t = u64;

/// The type of a file’s number of links.
pub type nlink_t = u64;

/// The type of a file’s timestamp (creation, modification, access, etc).
pub type time_t = i64;

/// The type of a file’s user ID.
pub type uid_t = u32;

/// The file’s base type, which gets displayed in the very first column of the
/// details output.
///
/// This type is set entirely by the filesystem, rather than relying on a
/// file’s contents. So “link” is a type, but “image” is just a type of
/// regular file. (See the `filetype` module for those checks.)
///
/// Its ordering is used when sorting by type.
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum Type {
    Directory,
    File,
    Link,
    Pipe,
    Socket,
    CharDevice,
    BlockDevice,
    Special,
}

impl Type {
    pub fn is_regular_file(self) -> bool {
        matches!(self, Self::File)
    }
}

/// The file’s Unix permission bitfield, with one entry per bit.
#[derive(Copy, Clone)]
pub struct Permissions {
    pub user_read:      bool,
    pub user_write:     bool,
    pub user_execute:   bool,

    pub group_read:     bool,
    pub group_write:    bool,
    pub group_execute:  bool,

    pub other_read:     bool,
    pub other_write:    bool,
    pub other_execute:  bool,

    pub sticky:         bool,
    pub setgid:         bool,
    pub setuid:         bool,
}

/// The three pieces of information that are displayed as a single column in
/// the details view. These values are fused together to make the output a
/// little more compressed.
#[derive(Copy, Clone)]
pub struct PermissionsPlus {
    pub file_type:   Type,
    pub permissions: Permissions,
    pub xattrs:      bool,
}

/// The permissions encoded as octal values
#[derive(Copy, Clone)]
pub struct OctalPermissions {
    pub permissions: Permissions,
}

/// A file’s number of hard links on the filesystem.
///
/// Under Unix, a file can exist on the filesystem only once but appear in
/// multiple directories. However, it’s rare (but occasionally useful!) for a
/// regular file to have a link count greater than 1, so we highlight the
/// block count specifically for this case.
#[derive(Copy, Clone)]
pub struct Links {

    /// The actual link count.
    pub count: nlink_t,

    /// Whether this file is a regular file with more than one hard link.
    pub multiple: bool,
}

/// A file’s inode. Every directory entry on a Unix filesystem has an inode,
/// including directories and links, so this is applicable to everything exa
/// can deal with.
#[derive(Copy, Clone)]
pub struct Inode(pub ino_t);

/// The number of blocks that a file takes up on the filesystem, if any.
#[derive(Copy, Clone)]
pub enum Blocks {

    /// This file has the given number of blocks.
    Some(blkcnt_t),

    /// This file isn’t of a type that can take up blocks.
    None,
}

/// The ID of the user that owns a file. This will only ever be a number;
/// looking up the username is done in the `display` module.
#[derive(Copy, Clone)]
pub struct User(pub uid_t);

/// The ID of the group that a file belongs to.
#[derive(Copy, Clone)]
pub struct Group(pub gid_t);

/// A file’s size, in bytes. This is usually formatted by the `number_prefix`
/// crate into something human-readable.
#[derive(Copy, Clone)]
pub enum Size {

    /// This file has a defined size.
    Some(u64),

    /// This file has no size, or has a size but we aren’t interested in it.
    ///
    /// Under Unix, directory entries that aren’t regular files will still
    /// have a file size. For example, a directory will just contain a list of
    /// its files as its “contents” and will be specially flagged as being a
    /// directory, rather than a file. However, seeing the “file size” of this
    /// data is rarely useful — I can’t think of a time when I’ve seen it and
    /// learnt something. So we discard it and just output “-” instead.
    ///
    /// See this answer for more: http://unix.stackexchange.com/a/68266
    None,

    /// This file is a block or character device, so instead of a size, print
    /// out the file’s major and minor device IDs.
    ///
    /// This is what ls does as well. Without it, the devices will just have
    /// file sizes of zero.
    DeviceIDs(DeviceIDs),
}

/// The major and minor device IDs that gets displayed for device files.
///
/// You can see what these device numbers mean:
/// - <http://www.lanana.org/docs/device-list/>
/// - <http://www.lanana.org/docs/device-list/devices-2.6+.txt>
#[derive(Copy, Clone)]
pub struct DeviceIDs {
    pub major: u8,
    pub minor: u8,
}

/// One of a file’s timestamps (created, accessed, or modified).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Time {
    pub seconds: time_t,
    pub nanoseconds: time_t,
}

/// A file’s status in a Git repository. Whether a file is in a repository or
/// not is handled by the Git module, rather than having a “null” variant in
/// this enum.
#[derive(PartialEq, Copy, Clone)]
pub enum GitStatus {

    /// This file hasn’t changed since the last commit.
    NotModified,

    /// This file didn’t exist for the last commit, and is not specified in
    /// the ignored files list.
    New,

    /// A file that’s been modified since the last commit.
    Modified,

    /// A deleted file. This can’t ever be shown, but it’s here anyway!
    Deleted,

    /// A file that Git has tracked a rename for.
    Renamed,

    /// A file that’s had its type (such as the file permissions) changed.
    TypeChange,

    /// A file that’s ignored (that matches a line in .gitignore)
    Ignored,

    /// A file that’s updated but unmerged.
    Conflicted,
}

/// A file’s complete Git status. It’s possible to make changes to a file, add
/// it to the staging area, then make *more* changes, so we need to list each
/// file’s status for both of these.
#[derive(Copy, Clone)]
pub struct Git {
    pub staged:   GitStatus,
    pub unstaged: GitStatus,
}

impl Default for Git {

    /// Create a Git status for a file with nothing done to it.
    fn default() -> Self {
        Self {
            staged: GitStatus::NotModified,
            unstaged: GitStatus::NotModified,
        }
    }
}
<commit_msg>updated links with markdown highlighting<commit_after>//! Wrapper types for the values returned from `File`s.
//!
//! The methods of `File` that return information about the entry on the
//! filesystem -- size, modification date, block count, or Git status -- used
//! to just return these as formatted strings, but this became inflexible once
//! customisable output styles landed.
//!
//! Instead, they will return a wrapper type from this module, which tags the
//! type with what field it is while containing the actual raw value.
//!
//! The `output::details` module, among others, uses these types to render and
//! display the information as formatted strings.

// C-style `blkcnt_t` types don’t follow Rust’s rules!
#![allow(non_camel_case_types)]
#![allow(clippy::struct_excessive_bools)]

/// The type of a file’s block count.
pub type blkcnt_t = u64;

/// The type of a file’s group ID.
pub type gid_t = u32;

/// The type of a file’s inode.
pub type ino_t = u64;

/// The type of a file’s number of links.
pub type nlink_t = u64;

/// The type of a file’s timestamp (creation, modification, access, etc).
pub type time_t = i64;

/// The type of a file’s user ID.
pub type uid_t = u32;

/// The file’s base type, which gets displayed in the very first column of the
/// details output.
///
/// This type is set entirely by the filesystem, rather than relying on a
/// file’s contents. So “link” is a type, but “image” is just a type of
/// regular file. (See the `filetype` module for those checks.)
///
/// Its ordering is used when sorting by type.
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum Type {
    Directory,
    File,
    Link,
    Pipe,
    Socket,
    CharDevice,
    BlockDevice,
    Special,
}

impl Type {
    pub fn is_regular_file(self) -> bool {
        matches!(self, Self::File)
    }
}

/// The file’s Unix permission bitfield, with one entry per bit.
#[derive(Copy, Clone)]
pub struct Permissions {
    pub user_read:      bool,
    pub user_write:     bool,
    pub user_execute:   bool,

    pub group_read:     bool,
    pub group_write:    bool,
    pub group_execute:  bool,

    pub other_read:     bool,
    pub other_write:    bool,
    pub other_execute:  bool,

    pub sticky:         bool,
    pub setgid:         bool,
    pub setuid:         bool,
}

/// The three pieces of information that are displayed as a single column in
/// the details view. These values are fused together to make the output a
/// little more compressed.
#[derive(Copy, Clone)]
pub struct PermissionsPlus {
    pub file_type:   Type,
    pub permissions: Permissions,
    pub xattrs:      bool,
}

/// The permissions encoded as octal values
#[derive(Copy, Clone)]
pub struct OctalPermissions {
    pub permissions: Permissions,
}

/// A file’s number of hard links on the filesystem.
///
/// Under Unix, a file can exist on the filesystem only once but appear in
/// multiple directories. However, it’s rare (but occasionally useful!) for a
/// regular file to have a link count greater than 1, so we highlight the
/// block count specifically for this case.
#[derive(Copy, Clone)]
pub struct Links {

    /// The actual link count.
    pub count: nlink_t,

    /// Whether this file is a regular file with more than one hard link.
    pub multiple: bool,
}

/// A file’s inode. Every directory entry on a Unix filesystem has an inode,
/// including directories and links, so this is applicable to everything exa
/// can deal with.
#[derive(Copy, Clone)]
pub struct Inode(pub ino_t);

/// The number of blocks that a file takes up on the filesystem, if any.
#[derive(Copy, Clone)]
pub enum Blocks {

    /// This file has the given number of blocks.
    Some(blkcnt_t),

    /// This file isn’t of a type that can take up blocks.
    None,
}

/// The ID of the user that owns a file. This will only ever be a number;
/// looking up the username is done in the `display` module.
#[derive(Copy, Clone)]
pub struct User(pub uid_t);

/// The ID of the group that a file belongs to.
#[derive(Copy, Clone)]
pub struct Group(pub gid_t);

/// A file’s size, in bytes. This is usually formatted by the `number_prefix`
/// crate into something human-readable.
#[derive(Copy, Clone)]
pub enum Size {

    /// This file has a defined size.
    Some(u64),

    /// This file has no size, or has a size but we aren’t interested in it.
    ///
    /// Under Unix, directory entries that aren’t regular files will still
    /// have a file size. For example, a directory will just contain a list of
    /// its files as its “contents” and will be specially flagged as being a
    /// directory, rather than a file. However, seeing the “file size” of this
    /// data is rarely useful — I can’t think of a time when I’ve seen it and
    /// learnt something. So we discard it and just output “-” instead.
    ///
    /// See this answer for more: <http://unix.stackexchange.com/a/68266>
    None,

    /// This file is a block or character device, so instead of a size, print
    /// out the file’s major and minor device IDs.
    ///
    /// This is what ls does as well. Without it, the devices will just have
    /// file sizes of zero.
    DeviceIDs(DeviceIDs),
}

/// The major and minor device IDs that gets displayed for device files.
///
/// You can see what these device numbers mean:
/// - <http://www.lanana.org/docs/device-list/>
/// - <http://www.lanana.org/docs/device-list/devices-2.6+.txt>
#[derive(Copy, Clone)]
pub struct DeviceIDs {
    pub major: u8,
    pub minor: u8,
}

/// One of a file’s timestamps (created, accessed, or modified).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Time {
    pub seconds: time_t,
    pub nanoseconds: time_t,
}

/// A file’s status in a Git repository. Whether a file is in a repository or
/// not is handled by the Git module, rather than having a “null” variant in
/// this enum.
#[derive(PartialEq, Copy, Clone)]
pub enum GitStatus {

    /// This file hasn’t changed since the last commit.
    NotModified,

    /// This file didn’t exist for the last commit, and is not specified in
    /// the ignored files list.
    New,

    /// A file that’s been modified since the last commit.
    Modified,

    /// A deleted file. This can’t ever be shown, but it’s here anyway!
    Deleted,

    /// A file that Git has tracked a rename for.
    Renamed,

    /// A file that’s had its type (such as the file permissions) changed.
    TypeChange,

    /// A file that’s ignored (that matches a line in .gitignore)
    Ignored,

    /// A file that’s updated but unmerged.
    Conflicted,
}

/// A file’s complete Git status. It’s possible to make changes to a file, add
/// it to the staging area, then make *more* changes, so we need to list each
/// file’s status for both of these.
#[derive(Copy, Clone)]
pub struct Git {
    pub staged:   GitStatus,
    pub unstaged: GitStatus,
}

impl Default for Git {

    /// Create a Git status for a file with nothing done to it.
    fn default() -> Self {
        Self {
            staged: GitStatus::NotModified,
            unstaged: GitStatus::NotModified,
        }
    }
}
<|endoftext|>


<commit_before>//! Create or redefine SQL functions
use std::ffi::{CStr};
use std::mem;
use std::ptr;
use std::str;
use libc::{c_int, c_double, c_char};

use ffi;
pub use ffi::sqlite3_context as sqlite3_context;
pub use ffi::sqlite3_value as sqlite3_value;
pub use ffi::sqlite3_value_type as sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type as sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        match str_to_cstring(self) {
            Ok(c_str) => ffi::sqlite3_result_text(ctx, c_str.as_ptr(), length as c_int,
                                                ffi::SQLITE_TRANSIENT()),
            Err(_)    => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        ffi::sqlite3_result_blob(
            ctx, mem::transmute(self.as_ptr()), self.len() as c_int, ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT || sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str
                .map(|s| { s.to_string() })
                .map_err(|e| { SqliteError{code: 0, message: e.to_string()} })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL ||
            T::parameter_has_valid_sqlite_type(v)
    }
}

// sqlite3_user_data
// sqlite3_get_auxdata
// sqlite3_set_auxdata

pub type ScalarFunc =
    Option<extern "C" fn (ctx: *mut sqlite3_context, argc: c_int, argv: *mut *mut sqlite3_value)>;

impl SqliteConnection {
    // TODO pApp
    pub fn create_scalar_function(&self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    pub fn create_scalar_function(&mut self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(), c_name.as_ptr(), n_arg, flags, ptr::null_mut(), x_func, None, None, None)
        };
        self.decode_result(r)
    }
}

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

    use std::boxed::Box;
    use std::ffi::{CString};
    use std::mem;
    use libc::{c_int, c_double, c_void};
    use self::regex::Regex;

    use SqliteConnection;
    use ffi;
    use ffi::sqlite3_context as sqlite3_context;
    use ffi::sqlite3_value as sqlite3_value;
    use functions::{FromValue,ToResult};

    extern "C" fn half(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let arg = *argv.offset(0);
            if c_double::parameter_has_valid_sqlite_type(arg) {
                let value = c_double::parameter_value(arg).unwrap() / 2f64;
                value.set_result(ctx);
            } else {
                ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISMATCH);
            }
        }
    }

    #[test]
    fn test_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, Some(half)).unwrap();
        let result = db.query_row("SELECT half(6)",
                                           &[],
                                           |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    extern "C" fn regexp_free(raw: *mut c_void) {
        unsafe {
            Box::from_raw(raw);
        }
    }

    extern "C" fn regexp(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let mut re_ptr = ffi::sqlite3_get_auxdata(ctx, 0) as *const Regex;
            let mut re_opt = None;
            if re_ptr.is_null() {
                let raw = String::parameter_value(*argv.offset(0));
                if raw.is_err() {
                    let msg = CString::new(format!("{}", raw.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let comp = Regex::new(raw.unwrap().as_ref());
                if comp.is_err() {
                    let msg = CString::new(format!("{}", comp.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let re = comp.unwrap();
                re_ptr = &re as *const Regex;
                re_opt = Some(re);
            }

            let text = String::parameter_value(*argv.offset(1));
            if text.is_ok() {
                let text = text.unwrap();
                (*re_ptr).is_match(text.as_ref()).set_result(ctx);
            }

            if re_opt.is_some() {
                ffi::sqlite3_set_auxdata(ctx, 0, mem::transmute(Box::into_raw(Box::new(re_opt.unwrap()))), Some(regexp_free));
            }
        }
    }

    #[test]
    fn test_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("regexp", 2, true, Some(regexp)).unwrap();
        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                           &[],
                                           |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());
    }
}
<commit_msg>Fix segfault in regexp user function test<commit_after>//! Create or redefine SQL functions
use std::ffi::{CStr};
use std::mem;
use std::ptr;
use std::str;
use libc::{c_int, c_double, c_char};

use ffi;
pub use ffi::sqlite3_context as sqlite3_context;
pub use ffi::sqlite3_value as sqlite3_value;
pub use ffi::sqlite3_value_type as sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type as sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        match str_to_cstring(self) {
            Ok(c_str) => ffi::sqlite3_result_text(ctx, c_str.as_ptr(), length as c_int,
                                                ffi::SQLITE_TRANSIENT()),
            Err(_)    => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return
        }
        ffi::sqlite3_result_blob(
            ctx, mem::transmute(self.as_ptr()), self.len() as c_int, ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT || sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str
                .map(|s| { s.to_string() })
                .map_err(|e| { SqliteError{code: 0, message: e.to_string()} })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL ||
            T::parameter_has_valid_sqlite_type(v)
    }
}

// sqlite3_user_data
// sqlite3_get_auxdata
// sqlite3_set_auxdata

pub type ScalarFunc =
    Option<extern "C" fn (ctx: *mut sqlite3_context, argc: c_int, argv: *mut *mut sqlite3_value)>;

impl SqliteConnection {
    // TODO pApp
    pub fn create_scalar_function(&self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    pub fn create_scalar_function(&mut self, fn_name: &str, n_arg: c_int, deterministic: bool, x_func: ScalarFunc) -> SqliteResult<()> {
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(), c_name.as_ptr(), n_arg, flags, ptr::null_mut(), x_func, None, None, None)
        };
        self.decode_result(r)
    }
}

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

    use std::boxed::Box;
    use std::ffi::{CString};
    use std::mem;
    use libc::{c_int, c_double, c_void};
    use self::regex::Regex;

    use SqliteConnection;
    use ffi;
    use ffi::sqlite3_context as sqlite3_context;
    use ffi::sqlite3_value as sqlite3_value;
    use functions::{FromValue,ToResult};

    extern "C" fn half(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let arg = *argv.offset(0);
            if c_double::parameter_has_valid_sqlite_type(arg) {
                let value = c_double::parameter_value(arg).unwrap() / 2f64;
                value.set_result(ctx);
            } else {
                ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISMATCH);
            }
        }
    }

    #[test]
    fn test_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, Some(half)).unwrap();
        let result = db.query_row("SELECT half(6)",
                                           &[],
                                           |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    extern "C" fn regexp_free(raw: *mut c_void) {
        let _: Box<Regex> = unsafe {
            Box::from_raw(mem::transmute(raw))
        };
    }

    extern "C" fn regexp(ctx: *mut sqlite3_context, _: c_int, argv: *mut *mut sqlite3_value) {
        unsafe {
            let mut re_ptr = ffi::sqlite3_get_auxdata(ctx, 0) as *const Regex;
            let need_re = re_ptr.is_null();
            if need_re {
                let raw = String::parameter_value(*argv.offset(0));
                if raw.is_err() {
                    let msg = CString::new(format!("{}", raw.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let comp = Regex::new(raw.unwrap().as_ref());
                if comp.is_err() {
                    let msg = CString::new(format!("{}", comp.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx, msg.as_ptr(), -1);
                    return
                }
                let re = Box::new(comp.unwrap());
                re_ptr = Box::into_raw(re);
            }

            let text = String::parameter_value(*argv.offset(1));
            if text.is_ok() {
                let text = text.unwrap();
                (*re_ptr).is_match(text.as_ref()).set_result(ctx);
            }

            if need_re {
                ffi::sqlite3_set_auxdata(ctx, 0, mem::transmute(re_ptr), Some(regexp_free));
            }
        }
    }

    #[test]
    fn test_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("regexp", 2, true, Some(regexp)).unwrap();
        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                           &[],
                                           |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());
    }
}
<|endoftext|>