<commit_before>extern crate nalgebra as na;
extern crate nkinematics as nk;
extern crate urdf_rs;
extern crate alga;

use alga::general::Real;
use std::collections::HashMap;

pub fn create_axis_from_vec3<T>(vec3: [f64; 3]) -> na::Unit<na::Vector3<T>>
    where T: Real
{
    na::Unit::<_>::new_normalize(na::Vector3::new(na::convert(vec3[0]),
                                                  na::convert(vec3[1]),
                                                  na::convert(vec3[2])))
}

pub fn create_linked_joint_from_urdf_joint<T>(joint: &urdf_rs::Joint) -> nk::LinkedJoint<T>
    where T: Real
{
    nk::LinkedJointBuilder::<T>::new()
        .joint(&joint.name,
               match joint.joint_type {
                   urdf_rs::JointType::Revolute => {
                       nk::JointType::Rotational {
                           axis: create_axis_from_vec3(joint.axis.xyz_as_array()),
                       }
                   }
                   urdf_rs::JointType::Prismatic => {
                       nk::JointType::Linear {
                           axis: create_axis_from_vec3(joint.axis.xyz_as_array()),
                       }
                   }
                   _ => nk::JointType::Fixed,
               })
        .name(&joint.child.link)
        .finalize()
}

fn get_joint_until_root<'a, 'b>(end_name: &'a str,
                                parent_joint_map: &'b HashMap<&str, &urdf_rs::Joint>)
                                -> Vec<&'b urdf_rs::Joint> {
    let mut ret = Vec::new();
    let mut parent_link_name = end_name;
    while let Some(joint) = parent_joint_map.get(&parent_link_name) {
        ret.push(*joint);
        parent_link_name = &joint.parent.link;
    }
    ret.reverse();
    ret
}

pub fn create_serial_linked_joints_vec<T>(robot: &urdf_rs::Robot) -> Vec<Vec<nk::LinkedJoint<T>>>
    where T: Real
{
    // find end links
    let mut link_map = HashMap::new();
    for l in robot.links.iter() {
        link_map.insert(&l.name, l);
    }
    let mut child_joint_map = HashMap::<&str, &urdf_rs::Joint>::new();
    for j in robot.joints.iter() {
        child_joint_map.insert(&j.child.link, j);
    }
    for joint in robot.joints.iter() {
        link_map.remove(&joint.parent.link);
    }
    // link_map contains end links only here
    link_map.keys()
        .map(|end_name| {
                 get_joint_until_root(&end_name, &child_joint_map)
                     .iter()
                     .map(|urdf_joint| create_linked_joint_from_urdf_joint(urdf_joint))
                     .collect()
             })
        .collect()
}

#[test]
fn it_works() {
    let robo = urdf_rs::read_file("sample.urdf").unwrap();
    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 7);
    let linked_joints = robo.joints
        .iter()
        .map(|joint| create_linked_joint_from_urdf_joint::<f32>(joint))
        .collect();
    let mut lf1 = nk::LinkedFrame::new(&robo.name);
    lf1.linked_joints = linked_joints;

    let lj_vec_vec = create_serial_linked_joints_vec::<f32>(&robo);
    assert_eq!(lj_vec_vec.len(), 1);
    assert_eq!(lj_vec_vec[0].len(), 6);
}
<commit_msg>Support link transform<commit_after>extern crate nalgebra as na;
extern crate nkinematics as nk;
extern crate urdf_rs;
extern crate alga;

use alga::general::Real;
use std::collections::HashMap;

pub fn axis_from<T>(array3: [f64; 3]) -> na::Unit<na::Vector3<T>>
    where T: Real
{
    na::Unit::<_>::new_normalize(na::Vector3::new(na::convert(array3[0]),
                                                  na::convert(array3[1]),
                                                  na::convert(array3[2])))
}

pub fn quaternion_from<T>(array3: [f64; 3]) -> na::UnitQuaternion<T>
    where T: Real
{
    na::UnitQuaternion::from_euler_angles(na::convert(array3[0]),
                                          na::convert(array3[1]),
                                          na::convert(array3[2]))
}

pub fn translation_from<T>(array3: [f64; 3]) -> na::Translation3<T>
    where T: Real
{
    na::Translation3::new(na::convert(array3[0]),
                          na::convert(array3[1]),
                          na::convert(array3[2]))
}

pub fn create_linked_joint_from_urdf_joint<T>(joint: &urdf_rs::Joint) -> nk::LinkedJoint<T>
    where T: Real
{
    nk::LinkedJointBuilder::<T>::new()
        .joint(&joint.name,
               match joint.joint_type {
                   urdf_rs::JointType::Revolute => {
                       nk::JointType::Rotational { axis: axis_from(joint.axis.xyz) }
                   }
                   urdf_rs::JointType::Prismatic => {
                       nk::JointType::Linear { axis: axis_from(joint.axis.xyz) }
                   }
                   _ => nk::JointType::Fixed,
               })
        .name(&joint.child.link)
        .rotation(quaternion_from(joint.origin.rpy))
        .translation(translation_from(joint.origin.xyz))
        .finalize()
}

fn get_joint_until_root<'a, 'b>(end_name: &'a str,
                                parent_joint_map: &'b HashMap<&str, &urdf_rs::Joint>)
                                -> Vec<&'b urdf_rs::Joint> {
    let mut ret = Vec::new();
    let mut parent_link_name = end_name;
    while let Some(joint) = parent_joint_map.get(&parent_link_name) {
        ret.push(*joint);
        parent_link_name = &joint.parent.link;
    }
    ret.reverse();
    ret
}

pub fn create_serial_linked_joints_vec<T>(robot: &urdf_rs::Robot) -> Vec<Vec<nk::LinkedJoint<T>>>
    where T: Real
{
    // find end links
    let mut link_map = HashMap::new();
    for l in robot.links.iter() {
        link_map.insert(&l.name, l);
    }
    let mut child_joint_map = HashMap::<&str, &urdf_rs::Joint>::new();
    for j in robot.joints.iter() {
        child_joint_map.insert(&j.child.link, j);
    }
    for joint in robot.joints.iter() {
        link_map.remove(&joint.parent.link);
    }
    // link_map contains end links only here
    link_map
        .keys()
        .map(|end_name| {
                 get_joint_until_root(&end_name, &child_joint_map)
                     .iter()
                     .map(|urdf_joint| create_linked_joint_from_urdf_joint(urdf_joint))
                     .collect()
             })
        .collect()
}

#[test]
fn it_works() {
    let robo = urdf_rs::read_file("sample.urdf").unwrap();
    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 7);
    let linked_joints = robo.joints
        .iter()
        .map(|joint| create_linked_joint_from_urdf_joint::<f32>(joint))
        .collect();
    let mut lf1 = nk::LinkedFrame::new(&robo.name);
    lf1.linked_joints = linked_joints;

    let lj_vec_vec = create_serial_linked_joints_vec::<f32>(&robo);
    assert_eq!(lj_vec_vec.len(), 1);
    assert_eq!(lj_vec_vec[0].len(), 6);
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::{io, slice, str};

use tokio_core::io::EasyBuf;

use httparse;

pub struct Response {
    status_code: u16,
    // TODO: use a small vec to avoid this unconditional allocation
    headers: Vec<(Slice, Slice)>,
    data: EasyBuf,
}

type Slice = (usize, usize);

impl Response {

    pub fn status_code(&self) -> u16 {
        self.status_code
    }

    pub fn content_length(&self) -> Option<usize> {
        self.headers()
            .find(|h| h.0.to_ascii_lowercase().as_str() == "content-length")
            .map(|h| {
                let v = ::std::str::from_utf8(&h.1).unwrap();
                v.parse::<usize>().ok()
            }).and_then(|v| v)
    }

    pub fn append_data(&mut self, buf: &[u8]) {
        self.data.get_mut().extend_from_slice(buf);
    }

    fn headers(&self) -> ResponseHeaders {
        ResponseHeaders {
            headers: self.headers.iter(),
            res: self,
        }
    }

    fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data.as_slice()[slice.0..slice.1]
    }
}

pub fn decode(buf: &mut EasyBuf) -> io::Result<Option<Response>> {
    let (status_code, headers, amt) = {
        let mut headers = [httparse::EMPTY_HEADER; 16];
        let mut r = httparse::Response::new(&mut headers);

        let status = try!(r.parse(buf.as_slice()).map_err(|e| {
            let msg = format!("failed to parse http response: {:?}", e);
            io::Error::new(io::ErrorKind::Other, msg)
        }));

        let amt = match status {
            httparse::Status::Complete(amt) => amt,
            httparse::Status::Partial => return Ok(None),
        };

        let toslice = |a: &[u8]| {
            let start = a.as_ptr() as usize - buf.as_slice().as_ptr() as usize;
            assert!(start < buf.len());
            (start, start + a.len())
        };

        let status_code = r.code.unwrap();
        //let reason_phrase = toslice(r.reason.unwrap().as_bytes());
        let headers = r.headers
            .iter()
            .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
            .collect();

        (status_code, headers, amt)
    };

    let response = Response {
        status_code: status_code,
        headers: headers,
        data: buf.drain_to(amt)
    };

    Ok(response.into())
}

pub fn encode(msg: Response, buf: &mut Vec<u8>) {
    buf.extend_from_slice(msg.data.as_ref());
}

pub struct ResponseHeaders<'res> {
    headers: slice::Iter<'res, (Slice, Slice)>,
    res: &'res Response,
}

impl<'res> Iterator for ResponseHeaders<'res> {
    type Item = (&'res str, &'res [u8]);

    fn next(&mut self) -> Option<(&'res str, &'res [u8])> {
        self.headers.next().map(|&(ref a, ref b)| {
            let a = self.res.slice(a);
            let b = self.res.slice(b);
            (str::from_utf8(a).unwrap(), b)
        })
    }
}
<commit_msg>avoid one<commit_after>use std::ascii::AsciiExt;
use std::{io, slice, str};

use tokio_core::io::EasyBuf;

use httparse;

pub struct Response {
    status_code: u16,
    // TODO: use a small vec to avoid this unconditional allocation
    headers: Vec<(Slice, Slice)>,
    data: EasyBuf,
}

type Slice = (usize, usize);

impl Response {

    pub fn status_code(&self) -> u16 {
        self.status_code
    }

    pub fn content_length(&self) -> Option<usize> {
        self.headers()
            .find(|h| h.0.to_ascii_lowercase().as_str() == "content-length")
            .and_then(|h| {
                let v = ::std::str::from_utf8(&h.1).unwrap();
                v.parse::<usize>().ok()
            })
    }

    pub fn append_data(&mut self, buf: &[u8]) {
        self.data.get_mut().extend_from_slice(buf);
    }

    fn headers(&self) -> ResponseHeaders {
        ResponseHeaders {
            headers: self.headers.iter(),
            res: self,
        }
    }

    fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data.as_slice()[slice.0..slice.1]
    }
}

pub fn decode(buf: &mut EasyBuf) -> io::Result<Option<Response>> {
    let (status_code, headers, amt) = {
        let mut headers = [httparse::EMPTY_HEADER; 16];
        let mut r = httparse::Response::new(&mut headers);

        let status = try!(r.parse(buf.as_slice()).map_err(|e| {
            let msg = format!("failed to parse http response: {:?}", e);
            io::Error::new(io::ErrorKind::Other, msg)
        }));

        let amt = match status {
            httparse::Status::Complete(amt) => amt,
            httparse::Status::Partial => return Ok(None),
        };

        let toslice = |a: &[u8]| {
            let start = a.as_ptr() as usize - buf.as_slice().as_ptr() as usize;
            assert!(start < buf.len());
            (start, start + a.len())
        };

        let status_code = r.code.unwrap();
        //let reason_phrase = toslice(r.reason.unwrap().as_bytes());
        let headers = r.headers
            .iter()
            .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
            .collect();

        (status_code, headers, amt)
    };

    let response = Response {
        status_code: status_code,
        headers: headers,
        data: buf.drain_to(amt)
    };

    Ok(response.into())
}

pub fn encode(msg: Response, buf: &mut Vec<u8>) {
    buf.extend_from_slice(msg.data.as_ref());
}

pub struct ResponseHeaders<'res> {
    headers: slice::Iter<'res, (Slice, Slice)>,
    res: &'res Response,
}

impl<'res> Iterator for ResponseHeaders<'res> {
    type Item = (&'res str, &'res [u8]);

    fn next(&mut self) -> Option<(&'res str, &'res [u8])> {
        self.headers.next().map(|&(ref a, ref b)| {
            let a = self.res.slice(a);
            let b = self.res.slice(b);
            (str::from_utf8(a).unwrap(), b)
        })
    }
}
<|endoftext|>


<commit_before>use super::plumbing::*;
use super::*;

use std::fmt::{self, Debug};

/// The `split` function takes arbitrary data and a closure that knows how to
/// split it, and turns this into a `ParallelIterator`.
///
/// # Examples
///
/// As a simple example, Rayon can recursively split ranges of indices
///
/// ```
/// use rayon::iter;
/// use rayon::prelude::*;
/// use std::ops::Range;
///
///
/// // We define a range of indices as follows
/// type Range1D = Range<usize>;
///
/// // Splitting it in two can be done like this
/// fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
///     // We are mathematically unable to split the range if there is only
///     // one point inside of it, but we could stop splitting before that.
///     if r.end - r.start <= 1 { return (r, None); }
///
///     // Here, our range is considered large enough to be splittable
///     let midpoint = r.start + (r.end - r.start) / 2;
///     (r.start..midpoint, Some(midpoint..r.end))
/// }
///
/// // By using iter::split, Rayon will split the range until it has enough work
/// // to feed the CPU cores, then give us the resulting sub-ranges
/// iter::split(0..4096, split_range1).for_each(|sub_range| {
///     // As our initial range had a power-of-two size, the final sub-ranges
///     // should have power-of-two sizes too
///     assert!((sub_range.end - sub_range.start).is_power_of_two());
/// });
/// ```
///
/// This recursive splitting can be extended to two or three dimensions,
/// to reproduce a classic "block-wise" parallelization scheme of graphics and
/// numerical simulations:
///
/// ```
/// # use rayon::iter;
/// # use rayon::prelude::*;
/// # use std::ops::Range;
/// # type Range1D = Range<usize>;
/// # fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
/// #     if r.end - r.start <= 1 { return (r, None); }
/// #     let midpoint = r.start + (r.end - r.start) / 2;
/// #     (r.start..midpoint, Some(midpoint..r.end))
/// # }
/// #
/// // A two-dimensional range of indices can be built out of two 1D ones
/// struct Range2D {
///     // Range of horizontal indices
///     pub rx: Range1D,
///
///     // Range of vertical indices
///     pub ry: Range1D,
/// }
///
/// // We want to recursively split them by the largest dimension until we have
/// // enough sub-ranges to feed our mighty multi-core CPU. This function
/// // carries out one such split.
/// fn split_range2(r2: Range2D) -> (Range2D, Option<Range2D>) {
///     // Decide on which axis (horizontal/vertical) the range should be split
///     let width = r2.rx.end - r2.rx.start;
///     let height = r2.ry.end - r2.ry.start;
///     if width >= height {
///         // This is a wide range, split it on the horizontal axis
///         let (split_rx, ry) = (split_range1(r2.rx), r2.ry);
///         let out1 = Range2D {
///             rx: split_rx.0,
///             ry: ry.clone(),
///         };
///         let out2 = split_rx.1.map(|rx| Range2D { rx, ry });
///         (out1, out2)
///     } else {
///         // This is a tall range, split it on the vertical axis
///         let (rx, split_ry) = (r2.rx, split_range1(r2.ry));
///         let out1 = Range2D {
///             rx: rx.clone(),
///             ry: split_ry.0,
///         };
///         let out2 = split_ry.1.map(|ry| Range2D { rx, ry, });
///         (out1, out2)
///     }
/// }
///
/// // Again, rayon can handle the recursive splitting for us
/// let range = Range2D { rx: 0..800, ry: 0..600 };
/// iter::split(range, split_range2).for_each(|sub_range| {
///     // If the sub-ranges were indeed split by the largest dimension, then
///     // if no dimension was twice larger than the other initially, this
///     // property will remain true in the final sub-ranges.
///     let width = sub_range.rx.end - sub_range.rx.start;
///     let height = sub_range.ry.end - sub_range.ry.start;
///     assert!((width < 2 * height) && (height < 2 * width));
/// });
/// ```
///
pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    Split {
        data: data,
        splitter: splitter,
    }
}

/// `Split` is a parallel iterator using arbitrary data and a splitting function.
/// This struct is created by the [`split()`] function.
///
/// [`split()`]: fn.split.html
#[derive(Clone)]
pub struct Split<D, S> {
    data: D,
    splitter: S,
}

impl<D: Debug, S> Debug for Split<D, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Split")
            .field("data", &self.data)
            .finish()
    }
}

impl<D, S> ParallelIterator for Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync + Send
{
    type Item = D;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer {
            data: self.data,
            splitter: &self.splitter,
        };
        bridge_unindexed(producer, consumer)
    }
}

struct SplitProducer<'a, D, S: 'a> {
    data: D,
    splitter: &'a S,
}

impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    type Item = D;

    fn split(mut self) -> (Self, Option<Self>) {
        let splitter = self.splitter;
        let (left, right) = splitter(self.data);
        self.data = left;
        (self,
         right.map(|data| {
                       SplitProducer {
                           data: data,
                           splitter: splitter,
                       }
                   }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume(self.data)
    }
}
<commit_msg>split: use floored division in example assertion<commit_after>use super::plumbing::*;
use super::*;

use std::fmt::{self, Debug};

/// The `split` function takes arbitrary data and a closure that knows how to
/// split it, and turns this into a `ParallelIterator`.
///
/// # Examples
///
/// As a simple example, Rayon can recursively split ranges of indices
///
/// ```
/// use rayon::iter;
/// use rayon::prelude::*;
/// use std::ops::Range;
///
///
/// // We define a range of indices as follows
/// type Range1D = Range<usize>;
///
/// // Splitting it in two can be done like this
/// fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
///     // We are mathematically unable to split the range if there is only
///     // one point inside of it, but we could stop splitting before that.
///     if r.end - r.start <= 1 { return (r, None); }
///
///     // Here, our range is considered large enough to be splittable
///     let midpoint = r.start + (r.end - r.start) / 2;
///     (r.start..midpoint, Some(midpoint..r.end))
/// }
///
/// // By using iter::split, Rayon will split the range until it has enough work
/// // to feed the CPU cores, then give us the resulting sub-ranges
/// iter::split(0..4096, split_range1).for_each(|sub_range| {
///     // As our initial range had a power-of-two size, the final sub-ranges
///     // should have power-of-two sizes too
///     assert!((sub_range.end - sub_range.start).is_power_of_two());
/// });
/// ```
///
/// This recursive splitting can be extended to two or three dimensions,
/// to reproduce a classic "block-wise" parallelization scheme of graphics and
/// numerical simulations:
///
/// ```
/// # use rayon::iter;
/// # use rayon::prelude::*;
/// # use std::ops::Range;
/// # type Range1D = Range<usize>;
/// # fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
/// #     if r.end - r.start <= 1 { return (r, None); }
/// #     let midpoint = r.start + (r.end - r.start) / 2;
/// #     (r.start..midpoint, Some(midpoint..r.end))
/// # }
/// #
/// // A two-dimensional range of indices can be built out of two 1D ones
/// struct Range2D {
///     // Range of horizontal indices
///     pub rx: Range1D,
///
///     // Range of vertical indices
///     pub ry: Range1D,
/// }
///
/// // We want to recursively split them by the largest dimension until we have
/// // enough sub-ranges to feed our mighty multi-core CPU. This function
/// // carries out one such split.
/// fn split_range2(r2: Range2D) -> (Range2D, Option<Range2D>) {
///     // Decide on which axis (horizontal/vertical) the range should be split
///     let width = r2.rx.end - r2.rx.start;
///     let height = r2.ry.end - r2.ry.start;
///     if width >= height {
///         // This is a wide range, split it on the horizontal axis
///         let (split_rx, ry) = (split_range1(r2.rx), r2.ry);
///         let out1 = Range2D {
///             rx: split_rx.0,
///             ry: ry.clone(),
///         };
///         let out2 = split_rx.1.map(|rx| Range2D { rx, ry });
///         (out1, out2)
///     } else {
///         // This is a tall range, split it on the vertical axis
///         let (rx, split_ry) = (r2.rx, split_range1(r2.ry));
///         let out1 = Range2D {
///             rx: rx.clone(),
///             ry: split_ry.0,
///         };
///         let out2 = split_ry.1.map(|ry| Range2D { rx, ry, });
///         (out1, out2)
///     }
/// }
///
/// // Again, rayon can handle the recursive splitting for us
/// let range = Range2D { rx: 0..800, ry: 0..600 };
/// iter::split(range, split_range2).for_each(|sub_range| {
///     // If the sub-ranges were indeed split by the largest dimension, then
///     // if no dimension was twice larger than the other initially, this
///     // property will remain true in the final sub-ranges.
///     let width = sub_range.rx.end - sub_range.rx.start;
///     let height = sub_range.ry.end - sub_range.ry.start;
///     assert!((width / 2 <= height) && (height / 2 <= width));
/// });
/// ```
///
pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    Split {
        data: data,
        splitter: splitter,
    }
}

/// `Split` is a parallel iterator using arbitrary data and a splitting function.
/// This struct is created by the [`split()`] function.
///
/// [`split()`]: fn.split.html
#[derive(Clone)]
pub struct Split<D, S> {
    data: D,
    splitter: S,
}

impl<D: Debug, S> Debug for Split<D, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Split")
            .field("data", &self.data)
            .finish()
    }
}

impl<D, S> ParallelIterator for Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync + Send
{
    type Item = D;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer {
            data: self.data,
            splitter: &self.splitter,
        };
        bridge_unindexed(producer, consumer)
    }
}

struct SplitProducer<'a, D, S: 'a> {
    data: D,
    splitter: &'a S,
}

impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    type Item = D;

    fn split(mut self) -> (Self, Option<Self>) {
        let splitter = self.splitter;
        let (left, right) = splitter(self.data);
        self.data = left;
        (self,
         right.map(|data| {
                       SplitProducer {
                           data: data,
                           splitter: splitter,
                       }
                   }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume(self.data)
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::Cell,
    collections::{HashMap, HashSet},
};

use super::behaviors::MouseBehavior;
use crate::{prelude::*, utils::SelectionMode as SelMode};

static ITEMS_PANEL: &'static str = "items_panel";
pub static LIST_VIEW: &'static str = "list_view";

/// The `ListViewState` generates the list box items and handles the selected indices.
#[derive(Default, AsAny)]
pub struct ListViewState {
    builder: WidgetBuildContext,
    count: usize,
    selected_entities: RefCell<HashSet<Entity>>,
    items_panel: Entity,
}

impl State for ListViewState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.items_panel = ctx
            .entity_of_child(ITEMS_PANEL)
            .expect("ListViewState.init: ItemsPanel child could not be found.");
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder(build_context, i);
                        let item = ListViewItem::new().build(build_context);

                        let mouse_behavior = MouseBehavior::new().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_widget(entity, false);
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        for index in ctx
            .widget()
            .get::<SelectedEntities>("selected_entities")
            .0
            .clone()
            .symmetric_difference(&*self.selected_entities.borrow())
        {
            let mut widget = ctx.get_widget(*index);
            let selected = !widget.get::<bool>("selected");
            widget.set("selected", selected);

            if selected {
                widget.get_mut::<Selector>("selector").set_state("selected");
            } else {
                widget.get_mut::<Selector>("selector").clear_state();
            }

            widget.update(false);
        }

        *self.selected_entities.borrow_mut() = ctx
            .widget()
            .get::<SelectedEntities>("selected_entities")
            .0
            .clone();
    }
}

/// The `ListViewItemState` handles the interaction and selection of a `ListViewItem`.
#[derive(Default, AsAny)]
pub struct ListViewItemState {
    request_selection_toggle: Cell<bool>,
}

impl ListViewItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ListViewItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let selected = *ctx.widget().get::<bool>("selected");

        let entity = ctx.entity;
        let index = ctx.index_as_child(entity).unwrap();

        let mut parent_entity = None;

        if let Some(parent) = &mut ctx.try_parent_from_id(LIST_VIEW) {
            let selection_mode = *parent.get::<SelectionMode>("selection_mode");
            // deselect item
            if selected {
                parent
                    .get_mut::<SelectedEntities>("selected_entities")
                    .0
                    .remove(&entity);
                parent
                    .get_mut::<SelectedIndices>("selected_indices")
                    .0
                    .remove(&index);
                return;
            }

            if parent
                .get::<SelectedEntities>("selected_entities")
                .0
                .contains(&entity)
                || selection_mode == SelMode::None
            {
                return;
            }

            if selection_mode == SelMode::Single {
                parent
                    .get_mut::<SelectedEntities>("selected_entities")
                    .0
                    .clear();
                parent
                    .get_mut::<SelectedIndices>("selected_indices")
                    .0
                    .clear();
            }

            parent
                .get_mut::<SelectedEntities>("selected_entities")
                .0
                .insert(entity);
            parent
                .get_mut::<SelectedIndices>("selected_indices")
                .0
                .insert(index);

            parent_entity = Some(parent.entity());
        }

        if let Some(parent) = parent_entity {
            ctx.push_event_strategy_by_entity(ChangedEvent(parent), parent, EventStrategy::Direct);
        }
    }
}

widget!(
    /// The `ListViewItem` describes an item inside of a `ListView`.
    ///
    /// **CSS element:** `list-view``
    ListViewItem<ListViewItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool,

        /// Sets or shares the parent id.
        parent: u32
    }
);

impl Template for ListViewItem {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ListViewItem")
            .style("list_view_item")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ListViewItemState>(id).toggle_selection();
                false
            })
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .build(ctx),
            )
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

widget!(
    /// The `ListView` is an items drawer widget with selectable items.
    ///
    /// **CSS element:** `items-widget`
    ListView<ListViewState> : ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the orientation property.
        orientation: Orientation,

        /// Sets or shares the item count.
        count: usize,

        /// Sets or shares the selection mode property.
        selection_mode: SelectionMode,

        /// Sets or shares the selected indices.
        selected_indices: SelectedIndices,

        /// Sets or shares the list of selected indices.
        selected_entities: SelectedEntities,

        /// Sets or shares the (wheel, scroll) delta property.
        delta: Point
    }
);

impl ListView {
    /// Define the template build function for the content of the ListViewItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ListView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let items_panel = Stack::new()
            .v_align("start")
            .id(ITEMS_PANEL)
            .orientation(id)
            .build(ctx);

        let scroll_viewer = ScrollViewer::new()
            .scroll_viewer_mode(("disabled", "auto"))
            .delta(id)
            .child(items_panel)
            .build(ctx);

        self.name("ListView")
            .style("list_view")
            .id(LIST_VIEW)
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(1.0)
            .border_brush(colors::BOMBAY_COLOR)
            .padding(2.0)
            .selection_mode("single")
            .selected_indices(HashSet::new())
            .selected_entities(HashSet::new())
            .delta(0.0)
            .orientation("vertical")
            .child(
                Container::new()
                    .background(id)
                    .border_radius(id)
                    .border_width(id)
                    .border_brush(id)
                    .padding(id)
                    .opacity(id)
                    .child(scroll_viewer)
                    .child(
                        ScrollIndicator::new()
                            .padding(2.0)
                            .content_id(items_panel.0)
                            .scroll_offset(scroll_viewer)
                            .opacity(id)
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<commit_msg>Remove default listview id.<commit_after>use std::{
    cell::Cell,
    collections::{HashMap, HashSet},
};

use super::behaviors::MouseBehavior;
use crate::{prelude::*, utils::SelectionMode as SelMode};

static ITEMS_PANEL: &'static str = "items_panel";

/// The `ListViewState` generates the list box items and handles the selected indices.
#[derive(Default, AsAny)]
pub struct ListViewState {
    builder: WidgetBuildContext,
    count: usize,
    selected_entities: RefCell<HashSet<Entity>>,
    items_panel: Entity,
}

impl State for ListViewState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.items_panel = ctx
            .entity_of_child(ITEMS_PANEL)
            .expect("ListViewState.init: ItemsPanel child could not be found.");
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder(build_context, i);
                        let item = ListViewItem::new().parent(entity.0).build(build_context);

                        let mouse_behavior = MouseBehavior::new().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_widget(entity, false);
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        for index in ctx
            .widget()
            .get::<SelectedEntities>("selected_entities")
            .0
            .clone()
            .symmetric_difference(&*self.selected_entities.borrow())
        {
            let mut widget = ctx.get_widget(*index);
            let selected = !widget.get::<bool>("selected");
            widget.set("selected", selected);

            if selected {
                widget.get_mut::<Selector>("selector").set_state("selected");
            } else {
                widget.get_mut::<Selector>("selector").clear_state();
            }

            widget.update(false);
        }

        *self.selected_entities.borrow_mut() = ctx
            .widget()
            .get::<SelectedEntities>("selected_entities")
            .0
            .clone();
    }
}

/// The `ListViewItemState` handles the interaction and selection of a `ListViewItem`.
#[derive(Default, AsAny)]
pub struct ListViewItemState {
    request_selection_toggle: Cell<bool>,
}

impl ListViewItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ListViewItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let selected = *ctx.widget().get::<bool>("selected");

        let entity = ctx.entity;
        let index = ctx.index_as_child(entity).unwrap();

        let parent_entity: Entity = (*ctx.widget().get::<u32>("parent")).into();

        let mut parent = ctx.get_widget(parent_entity);

        let selection_mode = *parent.get::<SelectionMode>("selection_mode");
        // deselect item
        if selected {
            parent
                .get_mut::<SelectedEntities>("selected_entities")
                .0
                .remove(&entity);
            parent
                .get_mut::<SelectedIndices>("selected_indices")
                .0
                .remove(&index);
            return;
        }

        if parent
            .get::<SelectedEntities>("selected_entities")
            .0
            .contains(&entity)
            || selection_mode == SelMode::None
        {
            return;
        }

        if selection_mode == SelMode::Single {
            parent
                .get_mut::<SelectedEntities>("selected_entities")
                .0
                .clear();
            parent
                .get_mut::<SelectedIndices>("selected_indices")
                .0
                .clear();
        }

        parent
            .get_mut::<SelectedEntities>("selected_entities")
            .0
            .insert(entity);
        parent
            .get_mut::<SelectedIndices>("selected_indices")
            .0
            .insert(index);

        ctx.push_event_strategy_by_entity(
            ChangedEvent(parent_entity),
            parent_entity,
            EventStrategy::Direct,
        );
    }
}

widget!(
    /// The `ListViewItem` describes an item inside of a `ListView`.
    ///
    /// **CSS element:** `list-view``
    ListViewItem<ListViewItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool,

        /// Sets or shares the parent id.
        parent: u32
    }
);

impl Template for ListViewItem {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ListViewItem")
            .style("list_view_item")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ListViewItemState>(id).toggle_selection();
                false
            })
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .build(ctx),
            )
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

widget!(
    /// The `ListView` is an items drawer widget with selectable items.
    ///
    /// **CSS element:** `items-widget`
    ListView<ListViewState> : ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the orientation property.
        orientation: Orientation,

        /// Sets or shares the item count.
        count: usize,

        /// Sets or shares the selection mode property.
        selection_mode: SelectionMode,

        /// Sets or shares the selected indices.
        selected_indices: SelectedIndices,

        /// Sets or shares the list of selected indices.
        selected_entities: SelectedEntities,

        /// Sets or shares the (wheel, scroll) delta property.
        delta: Point
    }
);

impl ListView {
    /// Define the template build function for the content of the ListViewItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ListView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let items_panel = Stack::new()
            .v_align("start")
            .id(ITEMS_PANEL)
            .orientation(id)
            .build(ctx);

        let scroll_viewer = ScrollViewer::new()
            .scroll_viewer_mode(("disabled", "auto"))
            .delta(id)
            .child(items_panel)
            .build(ctx);

        self.name("ListView")
            .style("list_view")
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(1.0)
            .border_brush(colors::BOMBAY_COLOR)
            .padding(2.0)
            .selection_mode("single")
            .selected_indices(HashSet::new())
            .selected_entities(HashSet::new())
            .delta(0.0)
            .orientation("vertical")
            .child(
                Container::new()
                    .background(id)
                    .border_radius(id)
                    .border_width(id)
                    .border_brush(id)
                    .padding(id)
                    .opacity(id)
                    .child(scroll_viewer)
                    .child(
                        ScrollIndicator::new()
                            .padding(2.0)
                            .content_id(items_panel.0)
                            .scroll_offset(scroll_viewer)
                            .opacity(id)
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<|endoftext|>


<commit_before>extern crate bytes;

use self::bytes::BytesMut;
use num::traits::Bounded;
use postgres_types::{FromSql, IsNull, ToSql, Type};

use std::error::Error;
use std::fmt;

use super::GenericDecimal;
use convert::TryToConvertFrom;
use fraction::GenericFraction;
use generic::GenericInteger;

use fraction::postgres_support::{fraction_to_sql_buf, read_i16, PG_MAX_PRECISION};

impl<'a, T, P> FromSql<'a> for GenericDecimal<T, P>
where
    T: Clone + GenericInteger + From<u16>,
    P: Copy + GenericInteger + Into<usize> + Bounded + TryToConvertFrom<i16> + fmt::Display,
{
    fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
        if raw.len() < 8 {
            return Err("unexpected data package from the database".into());
        }

        let scale: i16 = read_i16(&raw[6..8])?;
        let precision = if let Some(precision) = P::try_to_convert_from(scale) {
            precision
        } else {
            return Err(format!(
                "{} {};\n{} {};\n {} {};\n{} {}",
                r#"The precision of the source is too big: "#,
                scale,
                r#" your decimal type supports up to "#,
                P::max_value(),
                r#"you may increase the precision type size up to "usize", which is "#,
                usize::max_value(),
                r#"PostgreSQL supports precision up to "#,
                PG_MAX_PRECISION
            )
            .into());
        };

        Ok(GenericDecimal(
            <GenericFraction<T> as FromSql>::from_sql(ty, raw)?,
            precision,
        ))
    }

    accepts!(NUMERIC);
}

impl<T, P> ToSql for GenericDecimal<T, P>
where
    T: Clone + GenericInteger + From<u8> + fmt::Debug,
    P: Copy + GenericInteger + Into<usize> + fmt::Debug,
{
    fn to_sql(
        &self,
        ty: &Type,
        buf: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        match *self {
            GenericDecimal(ref fraction, precision) => {
                fraction_to_sql_buf(fraction, ty, buf, precision.into())
            }
        }
    }

    accepts!(NUMERIC);

    to_sql_checked!();
}

#[cfg(test)]
mod tests {
    use super::*;
    use {One, Zero};

    type Decimal = GenericDecimal<u128, u16>;

    const NUMERIC_OID: u32 = 1700;

    fn get_tests() -> Vec<(Decimal, &'static [u8])> {
        vec![
            (
                Decimal::from_str("-12345678901234").unwrap(),
                &[0, 4, 0, 3, 64, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
            ),
            (
                Decimal::from_str("-12345678").unwrap(),
                &[0, 2, 0, 1, 64, 0, 0, 0, 4, 210, 22, 46],
            ),
            (
                Decimal::from_str("-1000000000.0000000001").unwrap(),
                &[
                    0, 6, 0, 2, 64, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
                ],
            ),
            (
                Decimal::from_str("-1000000000").unwrap(),
                &[0, 1, 0, 2, 64, 0, 0, 0, 0, 10],
            ),
            (
                Decimal::from_str("-1234").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 4, 210],
            ),
            (
                Decimal::from_str("-256").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 1, 0],
            ),
            (
                Decimal::from_str("-42").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 0, 42],
            ),
            (
                Decimal::from_str("-1").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 0, 1],
            ),
            (
                Decimal::from_str("-0.5").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 1, 19, 136],
            ),
            (
                Decimal::from_str("-0.1").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 1, 3, 232],
            ),
            (
                Decimal::from_str("-0.66").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 2, 25, 200],
            ),
            (
                Decimal::from_str("-0.12345678901234").unwrap(),
                &[0, 4, 255, 255, 64, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
            ),
            (
                Decimal::from_str("-0.01").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 2, 0, 100],
            ),
            (
                Decimal::from_str("-0.2404").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 4, 9, 100],
            ),
            (
                Decimal::from_str("-0.000000001").unwrap(),
                &[0, 1, 255, 253, 64, 0, 0, 9, 3, 232],
            ),
            (
                Decimal::from_str("-12345678901234.12345678901234").unwrap(),
                &[
                    0, 8, 0, 3, 64, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
                    52, 13, 72,
                ],
            ),
            (Decimal::zero(), &[0, 0, 0, 0, 0, 0, 0, 0]),
            (Decimal::nan(), &[0, 0, 0, 0, 192, 0, 0, 0]),
            (
                Decimal::from_str("12345678901234.12345678901234").unwrap(),
                &[
                    0, 8, 0, 3, 0, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
                    52, 13, 72,
                ],
            ),
            (
                Decimal::from("0.000000001"),
                &[0, 1, 255, 253, 0, 0, 0, 9, 3, 232],
            ),
            (Decimal::from(0.2404), &[0, 1, 255, 255, 0, 0, 0, 4, 9, 100]),
            (Decimal::from(0.01), &[0, 1, 255, 255, 0, 0, 0, 2, 0, 100]),
            (Decimal::from(0.66), &[0, 1, 255, 255, 0, 0, 0, 2, 25, 200]),
            (
                Decimal::from_str("1000000.0000000000000001").unwrap(),
                &[
                    0, 6, 0, 1, 0, 0, 0, 16, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
                ],
            ),
            (
                Decimal::from_str("0.12345678901234").unwrap(),
                &[0, 4, 255, 255, 0, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
            ),
            (Decimal::from(0.1), &[0, 1, 255, 255, 0, 0, 0, 1, 3, 232]),
            (Decimal::from(0.5), &[0, 1, 255, 255, 0, 0, 0, 1, 19, 136]),
            (
                Decimal::from(0.55).set_precision(1),
                &[0, 1, 255, 255, 0, 0, 0, 1, 19, 136],
            ),
            (Decimal::one(), &[0, 1, 0, 0, 0, 0, 0, 0, 0, 1]),
            (Decimal::from(42), &[0, 1, 0, 0, 0, 0, 0, 0, 0, 42]),
            (Decimal::from(256), &[0, 1, 0, 0, 0, 0, 0, 0, 1, 0]),
            (Decimal::from(1234), &[0, 1, 0, 0, 0, 0, 0, 0, 4, 210]),
            (Decimal::from(1000000000), &[0, 1, 0, 2, 0, 0, 0, 0, 0, 10]),
            (
                Decimal::from("1000000000.0000000001"),
                &[
                    0, 6, 0, 2, 0, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
                ],
            ),
            (
                Decimal::from(12345678),
                &[0, 2, 0, 1, 0, 0, 0, 0, 4, 210, 22, 46],
            ),
            (
                Decimal::from(12345678901234u64),
                &[0, 4, 0, 3, 0, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
            ),
            (
                Decimal::from("0.33333333333333333333"),
                &[
                    0, 5, 255, 255, 0, 0, 0, 20, 13, 5, 13, 5, 13, 5, 13, 5, 13, 5,
                ],
            ),
        ]
    }

    #[test]
    fn test_from_sql() {
        let t = Type::from_oid(NUMERIC_OID).unwrap();
        for ref test in &get_tests() {
            assert_eq!(
                test.0,
                <Decimal as FromSql>::from_sql(&t, test.1).ok().unwrap()
            )
        }
    }

    #[test]
    fn test_to_sql() {
        let t = Type::from_oid(NUMERIC_OID).unwrap();
        let mut buf = BytesMut::with_capacity(1024);

        for ref test in &get_tests() {
            buf.clear();
            let res = <Decimal as ToSql>::to_sql(&test.0, &t, &mut buf)
                .ok()
                .unwrap();

            match res {
                IsNull::Yes => assert!(false),
                IsNull::No => assert!(true),
            };

            assert_eq!(&buf, &test.1);
        }
    }
}
<commit_msg>Use explicit types to make tests pass<commit_after>extern crate bytes;

use self::bytes::BytesMut;
use num::traits::Bounded;
use postgres_types::{FromSql, IsNull, ToSql, Type};

use std::error::Error;
use std::fmt;

use super::GenericDecimal;
use convert::TryToConvertFrom;
use fraction::GenericFraction;
use generic::GenericInteger;

use fraction::postgres_support::{fraction_to_sql_buf, read_i16, PG_MAX_PRECISION};

impl<'a, T, P> FromSql<'a> for GenericDecimal<T, P>
where
    T: Clone + GenericInteger + From<u16>,
    P: Copy + GenericInteger + Into<usize> + Bounded + TryToConvertFrom<i16> + fmt::Display,
{
    fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
        if raw.len() < 8 {
            return Err("unexpected data package from the database".into());
        }

        let scale: i16 = read_i16(&raw[6..8])?;
        let precision = if let Some(precision) = P::try_to_convert_from(scale) {
            precision
        } else {
            return Err(format!(
                "{} {};\n{} {};\n {} {};\n{} {}",
                r#"The precision of the source is too big: "#,
                scale,
                r#" your decimal type supports up to "#,
                P::max_value(),
                r#"you may increase the precision type size up to "usize", which is "#,
                usize::max_value(),
                r#"PostgreSQL supports precision up to "#,
                PG_MAX_PRECISION
            )
            .into());
        };

        Ok(GenericDecimal(
            <GenericFraction<T> as FromSql>::from_sql(ty, raw)?,
            precision,
        ))
    }

    accepts!(NUMERIC);
}

impl<T, P> ToSql for GenericDecimal<T, P>
where
    T: Clone + GenericInteger + From<u8> + fmt::Debug,
    P: Copy + GenericInteger + Into<usize> + fmt::Debug,
{
    fn to_sql(
        &self,
        ty: &Type,
        buf: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        match *self {
            GenericDecimal(ref fraction, precision) => {
                fraction_to_sql_buf(fraction, ty, buf, precision.into())
            }
        }
    }

    accepts!(NUMERIC);

    to_sql_checked!();
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;
    use {One, Zero};

    type Decimal = GenericDecimal<u128, u16>;

    const NUMERIC_OID: u32 = 1700;

    fn get_tests() -> Vec<(Decimal, &'static [u8])> {
        vec![
            (
                Decimal::from_str("-12345678901234").unwrap(),
                &[0, 4, 0, 3, 64, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
            ),
            (
                Decimal::from_str("-12345678").unwrap(),
                &[0, 2, 0, 1, 64, 0, 0, 0, 4, 210, 22, 46],
            ),
            (
                Decimal::from_str("-1000000000.0000000001").unwrap(),
                &[
                    0, 6, 0, 2, 64, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
                ],
            ),
            (
                Decimal::from_str("-1000000000").unwrap(),
                &[0, 1, 0, 2, 64, 0, 0, 0, 0, 10],
            ),
            (
                Decimal::from_str("-1234").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 4, 210],
            ),
            (
                Decimal::from_str("-256").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 1, 0],
            ),
            (
                Decimal::from_str("-42").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 0, 42],
            ),
            (
                Decimal::from_str("-1").unwrap(),
                &[0, 1, 0, 0, 64, 0, 0, 0, 0, 1],
            ),
            (
                Decimal::from_str("-0.5").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 1, 19, 136],
            ),
            (
                Decimal::from_str("-0.1").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 1, 3, 232],
            ),
            (
                Decimal::from_str("-0.66").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 2, 25, 200],
            ),
            (
                Decimal::from_str("-0.12345678901234").unwrap(),
                &[0, 4, 255, 255, 64, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
            ),
            (
                Decimal::from_str("-0.01").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 2, 0, 100],
            ),
            (
                Decimal::from_str("-0.2404").unwrap(),
                &[0, 1, 255, 255, 64, 0, 0, 4, 9, 100],
            ),
            (
                Decimal::from_str("-0.000000001").unwrap(),
                &[0, 1, 255, 253, 64, 0, 0, 9, 3, 232],
            ),
            (
                Decimal::from_str("-12345678901234.12345678901234").unwrap(),
                &[
                    0, 8, 0, 3, 64, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
                    52, 13, 72,
                ],
            ),
            (Decimal::zero(), &[0, 0, 0, 0, 0, 0, 0, 0]),
            (Decimal::nan(), &[0, 0, 0, 0, 192, 0, 0, 0]),
            (
                Decimal::from_str("12345678901234.12345678901234").unwrap(),
                &[
                    0, 8, 0, 3, 0, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
                    52, 13, 72,
                ],
            ),
            (
                Decimal::from("0.000000001"),
                &[0, 1, 255, 253, 0, 0, 0, 9, 3, 232],
            ),
            (
                Decimal::from(0.2404f64),
                &[0, 1, 255, 255, 0, 0, 0, 4, 9, 100],
            ),
            (
                Decimal::from(0.01f32),
                &[0, 1, 255, 255, 0, 0, 0, 2, 0, 100],
            ),
            (
                Decimal::from(0.66f32),
                &[0, 1, 255, 255, 0, 0, 0, 2, 25, 200],
            ),
            (
                Decimal::from_str("1000000.0000000000000001").unwrap(),
                &[
                    0, 6, 0, 1, 0, 0, 0, 16, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
                ],
            ),
            (
                Decimal::from_str("0.12345678901234").unwrap(),
                &[0, 4, 255, 255, 0, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
            ),
            (Decimal::from(0.1f32), &[0, 1, 255, 255, 0, 0, 0, 1, 3, 232]),
            (
                Decimal::from(0.5f32),
                &[0, 1, 255, 255, 0, 0, 0, 1, 19, 136],
            ),
            (
                Decimal::from(0.55f32).set_precision(1),
                &[0, 1, 255, 255, 0, 0, 0, 1, 19, 136],
            ),
            (Decimal::one(), &[0, 1, 0, 0, 0, 0, 0, 0, 0, 1]),
            (Decimal::from(42u8), &[0, 1, 0, 0, 0, 0, 0, 0, 0, 42]),
            (Decimal::from(256u16), &[0, 1, 0, 0, 0, 0, 0, 0, 1, 0]),
            (Decimal::from(1234u16), &[0, 1, 0, 0, 0, 0, 0, 0, 4, 210]),
            (
                Decimal::from(1000000000u64),
                &[0, 1, 0, 2, 0, 0, 0, 0, 0, 10],
            ),
            (
                Decimal::from("1000000000.0000000001"),
                &[
                    0, 6, 0, 2, 0, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
                ],
            ),
            (
                Decimal::from(12345678u32),
                &[0, 2, 0, 1, 0, 0, 0, 0, 4, 210, 22, 46],
            ),
            (
                Decimal::from(12345678901234u64),
                &[0, 4, 0, 3, 0, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
            ),
            (
                Decimal::from("0.33333333333333333333"),
                &[
                    0, 5, 255, 255, 0, 0, 0, 20, 13, 5, 13, 5, 13, 5, 13, 5, 13, 5,
                ],
            ),
        ]
    }

    #[test]
    fn test_from_sql() {
        let t = Type::from_oid(NUMERIC_OID).unwrap();
        for ref test in &get_tests() {
            assert_eq!(
                test.0,
                <Decimal as FromSql>::from_sql(&t, test.1).ok().unwrap()
            )
        }
    }

    #[test]
    fn test_to_sql() {
        let t = Type::from_oid(NUMERIC_OID).unwrap();
        let mut buf = BytesMut::with_capacity(1024);

        for ref test in &get_tests() {
            buf.clear();
            let res = <Decimal as ToSql>::to_sql(&test.0, &t, &mut buf)
                .ok()
                .unwrap();

            match res {
                IsNull::Yes => assert!(false),
                IsNull::No => assert!(true),
            };

            assert_eq!(&buf, &test.1);
        }
    }
}
<|endoftext|>


<commit_before>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Distribution};
use {Result, StatsError};

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical
{
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
}

impl Categorical
{
    pub fn new(prob_mass: &[f64]) -> Result<Categorical>
    {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
            })
        }
    }
}

impl Sample<f64> for Categorical
{
    /// Generate a random sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Categorical
{
    /// Generate a random independent sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Categorical
{
    /// Generate a random sample from the categorical distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Categorical, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Categorical::new(&[1.0, 2.0, 3.0]).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let draw = r.next_f64() * unsafe { self.cdf.get_unchecked(self.cdf.len() - 1) };
        let mut idx = 0;

        if draw == 0.0 {
            // skip zero-probability categories
            let mut el = unsafe { self.cdf.get_unchecked(idx) };
            while *el == 0.0 {
                // don't need bounds checking because we do not allow
                // creating Categorical distributions with all 0.0 probs
                idx += 1;
                el = unsafe { self.cdf.get_unchecked(idx) }
            }
        }
        let mut el = unsafe { self.cdf.get_unchecked(idx) };
        while draw > *el {
            idx += 1;
            el = unsafe { self.cdf.get_unchecked(idx) };
        }
        return idx as f64;
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use distribution::Categorical;

    fn try_create(prob_mass: &[f64]) -> Categorical {
        let n = Categorical::new(prob_mass);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let n = Categorical::new(prob_mass);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }
}<commit_msg>feat: impl cdf for categorical<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Discrete, Distribution};
use {Result, StatsError};

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical {
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
}

impl Categorical {
    pub fn new(prob_mass: &[f64]) -> Result<Categorical> {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
            })
        }
    }

    fn cdf_max(&self) -> f64 {
        *unsafe { self.cdf.get_unchecked(self.cdf.len() - 1) }
    }
}

impl Sample<f64> for Categorical {
    /// Generate a random sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Categorical {
    /// Generate a random independent sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Categorical {
    /// Generate a random sample from the categorical distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Categorical, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Categorical::new(&[1.0, 2.0, 3.0]).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let draw = r.next_f64() * self.cdf_max();
        let mut idx = 0;

        if draw == 0.0 {
            // skip zero-probability categories
            let mut el = unsafe { self.cdf.get_unchecked(idx) };
            while *el == 0.0 {
                // don't need bounds checking because we do not allow
                // creating Categorical distributions with all 0.0 probs
                idx += 1;
                el = unsafe { self.cdf.get_unchecked(idx) }
            }
        }
        let mut el = unsafe { self.cdf.get_unchecked(idx) };
        while draw > *el {
            idx += 1;
            el = unsafe { self.cdf.get_unchecked(idx) };
        }
        return idx as f64;
    }
}

impl Univariate<u64, f64> for Categorical {
    /// Calculates the cumulative distribution function for the categorical
    /// distribution at `x`
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > k` where `k` is the number of categories
    /// (i.e. the length of the `prob_mass` slice passed to the constructor)
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sum(p_j) from 0..x
    /// ```
    ///
    /// where `p_j` is the probability mass for the `j`th category
    fn cdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= self.cdf.len() as f64,
                format!("{}",
                        StatsError::ArgIntervalIncl("x", 0.0, self.cdf.len() as f64)));
        if x == self.cdf.len() as f64 {
            1.0
        } else {
            unsafe { self.cdf.get_unchecked(x as usize) / self.cdf_max() }
        }
    }
}

impl Min<u64> for Categorical {
    /// Returns the minimum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> u64 {
        0
    }
}

impl Max<u64> for Categorical {
    /// Returns the maximum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// n
    /// ```
    fn max(&self) -> u64 {
        self.cdf.len() as u64 - 1
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::fmt::Debug;
    use statistics::*;
    use distribution::{Univariate, Categorical};

    fn try_create(prob_mass: &[f64]) -> Categorical {
        let n = Categorical::new(prob_mass);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let n = Categorical::new(prob_mass);
        assert!(n.is_err());
    }

    fn test_case<T, F>(prob_mass: &[f64], expected: T, eval: F)
        where T: PartialEq + Debug,
              F: Fn(Categorical) -> T
    {
        let n = try_create(prob_mass);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }

    #[test]
    fn test_min_max() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 0, |x| x.min());
        test_case(&[4.0, 2.5, 2.5, 1.0], 3, |x| x.max());
    }

    #[test]
    fn test_cdf() {
        test_case(&[0.0, 3.0, 1.0, 1.0], 3.0 / 5.0, |x| x.cdf(1.5));
        test_case(&[1.0, 1.0, 1.0, 1.0], 0.25, |x| x.cdf(0.0));
        test_case(&[4.0, 2.5, 2.5, 1.0], 0.4, |x| x.cdf(0.8));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(3.2));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_low() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(-1.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_high() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.5));
    }
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::relay_directive::{MASK_ARG_NAME, PLURAL_ARG_NAME, RELAY_DIRECTIVE_NAME};
use common::{Diagnostic, DiagnosticsResult, NamedItem};
use errors::validate;
use fnv::FnvHashMap;
use graphql_ir::{
    ConstantValue, Directive, FragmentDefinition, FragmentSpread, OperationDefinition, Program,
    ValidationMessage, Validator, Value, VariableDefinition,
};
use interner::StringKey;
use schema::Schema;

pub fn validate_relay_directives(program: &Program) -> DiagnosticsResult<()> {
    let mut validator = RelayDirectiveValidation::new(program);
    validator.validate_program(program)
}

enum ArgumentDefinition<'ir> {
    Global(&'ir VariableDefinition),
    Local(&'ir VariableDefinition),
}

// This validtes both @relay(plural) and @relay(mask) usages
struct RelayDirectiveValidation<'program> {
    program: &'program Program,
    // TODO(T63626938): This assumes that each document is processed serially (not in parallel or concurrently)
    current_reachable_arguments: Vec<&'program VariableDefinition>,
}

fn find_relay_directive(directives: &[Directive]) -> Option<&Directive> {
    directives.named(*RELAY_DIRECTIVE_NAME)
}

impl<'program> RelayDirectiveValidation<'program> {
    fn new(program: &'program Program) -> Self {
        Self {
            program,
            current_reachable_arguments: Default::default(),
        }
    }

    /// For ...Fragment @relay(mask:false), disallow fragments with directives or local variables
    fn validate_unmask_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        let fragment = self.program.fragment(spread.fragment.item).unwrap();
        if !(fragment.directives.is_empty()
            || fragment.directives.len() == 1
                && fragment.directives[0].name.item == *RELAY_DIRECTIVE_NAME)
        {
            errs.push(
                Diagnostic::error(
                    ValidationMessage::InvalidUnmaskOnFragmentWithDirectives(),
                    spread.fragment.location,
                )
                .annotate("related location", fragment.name.location),
            )
        }

        self.current_reachable_arguments
            .extend(&fragment.used_global_variables);
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }

    /// For all reachable arguments in the unmaksed fragments, validate that for the variables with the same name:
    /// 1. They are either all global argument or all local arguments
    /// 2. Their types should be same, or one is the subset of the
    fn validate_reachable_arguments(
        &self,
        map: &mut FnvHashMap<StringKey, ArgumentDefinition<'program>>,
    ) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        for arg in &self.current_reachable_arguments {
            if let Some(prev_arg) = map.get(&arg.name.item) {
                match prev_arg {
                    ArgumentDefinition::Local(prev_arg) => errs.push(
                        Diagnostic::error(
                            ValidationMessage::InvalidUnmaskOnLocalAndGloablVariablesWithSameName(),
                            prev_arg.name.location,
                        )
                        .annotate("related location", arg.name.location),
                    ),
                    ArgumentDefinition::Global(prev_arg) => {
                        if !self
                            .program
                            .schema
                            .is_type_subtype_of(&prev_arg.type_, &arg.type_)
                            && !self
                                .program
                                .schema
                                .is_type_subtype_of(&arg.type_, &prev_arg.type_)
                        {
                            errs.push(Diagnostic::error(
                                ValidationMessage::InvalidUnmaskOnVariablesOfIncompatibleTypesWithSameName{
                                    prev_arg_type: self.program.schema.get_type_string(&prev_arg.type_),
                                    next_arg_type: self.program.schema.get_type_string(&arg.type_),
                                },
                                prev_arg.name.location,
                            ).annotate("related location", arg.name.location))
                        }
                    }
                }
            } else {
                map.insert(arg.name.item, ArgumentDefinition::Global(arg));
            }
        }
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }

    fn validate_relay_directives(&self, directives: &[Directive]) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        if let Some(directive) = find_relay_directive(directives) {
            for arg in &directive.arguments {
                if arg.name.item == *PLURAL_ARG_NAME || arg.name.item == *MASK_ARG_NAME {
                    match arg.value.item {
                        Value::Constant(ConstantValue::Boolean(_))
                        | Value::Constant(ConstantValue::Null()) => {}
                        _ => errs.push(Diagnostic::error(
                            ValidationMessage::InvalidRelayDirectiveArg(arg.name.item),
                            arg.value.location,
                        )),
                    }
                }
            }
        }
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }
}

impl Validator for RelayDirectiveValidation<'_> {
    const NAME: &'static str = "RelayDirectiveValidation";
    const VALIDATE_ARGUMENTS: bool = false;
    const VALIDATE_DIRECTIVES: bool = false;

    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        // Initialize arguments state for @relay(mask: false),
        self.current_reachable_arguments = Default::default();
        validate!(
            self.default_validate_fragment(fragment),
            self.validate_relay_directives(&fragment.directives),
            if self.current_reachable_arguments.is_empty() {
                Ok(())
            } else {
                let mut map = FnvHashMap::default();
                for variable in &fragment.used_global_variables {
                    map.insert(variable.name.item, ArgumentDefinition::Global(variable));
                }
                for variable in &fragment.variable_definitions {
                    map.insert(variable.name.item, ArgumentDefinition::Local(variable));
                }
                self.validate_reachable_arguments(&mut map)
            }
        )
    }

    fn validate_operation(&mut self, operation: &OperationDefinition) -> DiagnosticsResult<()> {
        // Initialize arguments state for @relay(mask: false),
        self.current_reachable_arguments = Default::default();
        validate!(
            self.default_validate_operation(&operation),
            if self.current_reachable_arguments.is_empty() {
                Ok(())
            } else {
                let mut map = FnvHashMap::default();
                for variable in &operation.variable_definitions {
                    map.insert(variable.name.item, ArgumentDefinition::Global(variable));
                }
                self.validate_reachable_arguments(&mut map)
            }
        )
    }

    fn validate_fragment_spread(&mut self, spread: &FragmentSpread) -> DiagnosticsResult<()> {
        validate!(
            if let Some(directive) = find_relay_directive(&spread.directives) {
                let mask_argument = directive.arguments.named(*MASK_ARG_NAME);
                if let Some(arg) = mask_argument {
                    match arg.value.item {
                        Value::Constant(ConstantValue::Boolean(val)) => {
                            if val {
                                Ok(())
                            } else {
                                self.validate_unmask_fragment_spread(spread)
                            }
                        }
                        Value::Constant(ConstantValue::Null()) => Ok(()),
                        _ => Err(vec![
                            Diagnostic::error(
                                ValidationMessage::InvalidRelayDirectiveArg(arg.name.item),
                                spread.fragment.location,
                            )
                            .annotate("related location", arg.value.location),
                        ]),
                    }
                } else {
                    Ok(())
                }
            } else {
                Ok(())
            },
            self.default_validate_fragment_spread(spread)
        )
    }
}
<commit_msg>Add fb-relay-transforms module and validation for @uri_prefetch<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::relay_directive::{MASK_ARG_NAME, PLURAL_ARG_NAME, RELAY_DIRECTIVE_NAME};
use common::{Diagnostic, DiagnosticsResult, NamedItem};
use errors::validate;
use fnv::FnvHashMap;
use graphql_ir::{
    ConstantValue, Directive, FragmentDefinition, FragmentSpread, OperationDefinition, Program,
    ValidationMessage, Validator, Value, VariableDefinition,
};
use interner::StringKey;
use schema::Schema;

pub fn validate_relay_directives(program: &Program) -> DiagnosticsResult<()> {
    let mut validator = RelayDirectiveValidation::new(program);
    validator.validate_program(program)
}

enum ArgumentDefinition<'ir> {
    Global(&'ir VariableDefinition),
    Local(&'ir VariableDefinition),
}

// This validates both @relay(plural) and @relay(mask) usages
struct RelayDirectiveValidation<'program> {
    program: &'program Program,
    // TODO(T63626938): This assumes that each document is processed serially (not in parallel or concurrently)
    current_reachable_arguments: Vec<&'program VariableDefinition>,
}

fn find_relay_directive(directives: &[Directive]) -> Option<&Directive> {
    directives.named(*RELAY_DIRECTIVE_NAME)
}

impl<'program> RelayDirectiveValidation<'program> {
    fn new(program: &'program Program) -> Self {
        Self {
            program,
            current_reachable_arguments: Default::default(),
        }
    }

    /// For ...Fragment @relay(mask:false), disallow fragments with directives or local variables
    fn validate_unmask_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        let fragment = self.program.fragment(spread.fragment.item).unwrap();
        if !(fragment.directives.is_empty()
            || fragment.directives.len() == 1
                && fragment.directives[0].name.item == *RELAY_DIRECTIVE_NAME)
        {
            errs.push(
                Diagnostic::error(
                    ValidationMessage::InvalidUnmaskOnFragmentWithDirectives(),
                    spread.fragment.location,
                )
                .annotate("related location", fragment.name.location),
            )
        }

        self.current_reachable_arguments
            .extend(&fragment.used_global_variables);
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }

    /// For all reachable arguments in the unmaksed fragments, validate that for the variables with the same name:
    /// 1. They are either all global argument or all local arguments
    /// 2. Their types should be same, or one is the subset of the
    fn validate_reachable_arguments(
        &self,
        map: &mut FnvHashMap<StringKey, ArgumentDefinition<'program>>,
    ) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        for arg in &self.current_reachable_arguments {
            if let Some(prev_arg) = map.get(&arg.name.item) {
                match prev_arg {
                    ArgumentDefinition::Local(prev_arg) => errs.push(
                        Diagnostic::error(
                            ValidationMessage::InvalidUnmaskOnLocalAndGloablVariablesWithSameName(),
                            prev_arg.name.location,
                        )
                        .annotate("related location", arg.name.location),
                    ),
                    ArgumentDefinition::Global(prev_arg) => {
                        if !self
                            .program
                            .schema
                            .is_type_subtype_of(&prev_arg.type_, &arg.type_)
                            && !self
                                .program
                                .schema
                                .is_type_subtype_of(&arg.type_, &prev_arg.type_)
                        {
                            errs.push(Diagnostic::error(
                                ValidationMessage::InvalidUnmaskOnVariablesOfIncompatibleTypesWithSameName{
                                    prev_arg_type: self.program.schema.get_type_string(&prev_arg.type_),
                                    next_arg_type: self.program.schema.get_type_string(&arg.type_),
                                },
                                prev_arg.name.location,
                            ).annotate("related location", arg.name.location))
                        }
                    }
                }
            } else {
                map.insert(arg.name.item, ArgumentDefinition::Global(arg));
            }
        }
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }

    fn validate_relay_directives(&self, directives: &[Directive]) -> DiagnosticsResult<()> {
        let mut errs = vec![];
        if let Some(directive) = find_relay_directive(directives) {
            for arg in &directive.arguments {
                if arg.name.item == *PLURAL_ARG_NAME || arg.name.item == *MASK_ARG_NAME {
                    match arg.value.item {
                        Value::Constant(ConstantValue::Boolean(_))
                        | Value::Constant(ConstantValue::Null()) => {}
                        _ => errs.push(Diagnostic::error(
                            ValidationMessage::InvalidRelayDirectiveArg(arg.name.item),
                            arg.value.location,
                        )),
                    }
                }
            }
        }
        if errs.is_empty() { Ok(()) } else { Err(errs) }
    }
}

impl Validator for RelayDirectiveValidation<'_> {
    const NAME: &'static str = "RelayDirectiveValidation";
    const VALIDATE_ARGUMENTS: bool = false;
    const VALIDATE_DIRECTIVES: bool = false;

    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        // Initialize arguments state for @relay(mask: false),
        self.current_reachable_arguments = Default::default();
        validate!(
            self.default_validate_fragment(fragment),
            self.validate_relay_directives(&fragment.directives),
            if self.current_reachable_arguments.is_empty() {
                Ok(())
            } else {
                let mut map = FnvHashMap::default();
                for variable in &fragment.used_global_variables {
                    map.insert(variable.name.item, ArgumentDefinition::Global(variable));
                }
                for variable in &fragment.variable_definitions {
                    map.insert(variable.name.item, ArgumentDefinition::Local(variable));
                }
                self.validate_reachable_arguments(&mut map)
            }
        )
    }

    fn validate_operation(&mut self, operation: &OperationDefinition) -> DiagnosticsResult<()> {
        // Initialize arguments state for @relay(mask: false),
        self.current_reachable_arguments = Default::default();
        validate!(
            self.default_validate_operation(&operation),
            if self.current_reachable_arguments.is_empty() {
                Ok(())
            } else {
                let mut map = FnvHashMap::default();
                for variable in &operation.variable_definitions {
                    map.insert(variable.name.item, ArgumentDefinition::Global(variable));
                }
                self.validate_reachable_arguments(&mut map)
            }
        )
    }

    fn validate_fragment_spread(&mut self, spread: &FragmentSpread) -> DiagnosticsResult<()> {
        validate!(
            if let Some(directive) = find_relay_directive(&spread.directives) {
                let mask_argument = directive.arguments.named(*MASK_ARG_NAME);
                if let Some(arg) = mask_argument {
                    match arg.value.item {
                        Value::Constant(ConstantValue::Boolean(val)) => {
                            if val {
                                Ok(())
                            } else {
                                self.validate_unmask_fragment_spread(spread)
                            }
                        }
                        Value::Constant(ConstantValue::Null()) => Ok(()),
                        _ => Err(vec![
                            Diagnostic::error(
                                ValidationMessage::InvalidRelayDirectiveArg(arg.name.item),
                                spread.fragment.location,
                            )
                            .annotate("related location", arg.value.location),
                        ]),
                    }
                } else {
                    Ok(())
                }
            } else {
                Ok(())
            },
            self.default_validate_fragment_spread(spread)
        )
    }
}
<|endoftext|>