<commit_before>use std::fmt;
use std::str::FromStr;

use mime_parse::{Mime, Parse};

use crate::{InvalidMime, MediaType, Value};

/// A parsed media range used to match media types.
///
/// Commonly found in the HTTP `Accept` header, these are used for agents
/// to indicate general classes of content that they can understand.
///
/// # Example
///
/// ```
/// use mime::MediaRange;
///
/// // Suppose this was parsed from an `Accept` header
/// let range = MediaRange::parse("text/*").unwrap();
///
/// // The formats of the resource that we have:
/// let formats = vec![
///     mime::APPLICATION_JSON,
///     mime::TEXT_PLAIN_UTF_8,
///     mime::TEXT_HTML,
/// ];
///
/// for format in &formats {
///     if range.matches(format) {
///         // This should print for the plain and HTML text...
///         println!("We could send in {:?} format!", format);
///     }
/// }
/// ```
#[derive(Clone, PartialEq)]
pub struct MediaRange {
    pub(super) mime: Mime,
}

impl MediaRange {
    /// Parse a string as a `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::MediaRange::parse("*/*").unwrap();
    /// assert_eq!(range, mime::STAR_STAR);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if the source is not a valid media range.
    #[inline]
    pub fn parse(source: impl Parse) -> Result<Self, InvalidMime> {
        mime_parse::parse(source, mime_parse::CanRange::Yes)
            .map(|mime| MediaRange { mime })
            .map_err(|e| InvalidMime { inner: e })
    }

    /// Get the top level media type for this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::TEXT_STAR;
    /// assert_eq!(range.type_(), "text");
    /// assert_eq!(range.type_(), mime::TEXT);
    /// ```
    #[inline]
    pub fn type_(&self) -> &str {
        self.mime.type_()
    }

    /// Get the subtype of this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::TEXT_STAR;
    ///
    /// assert_eq!(range.subtype(), "*");
    /// assert_eq!(range.subtype(), mime::STAR);
    ///
    /// let exact = mime::MediaRange::from(mime::TEXT_PLAIN);
    /// assert_eq!(exact.subtype(), mime::PLAIN);
    /// assert_eq!(exact.subtype(), "plain");
    /// ```
    #[inline]
    pub fn subtype(&self) -> &str {
        self.mime.subtype()
    }

    /// Get an optional +suffix for this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let svg = mime::MediaRange::from(mime::IMAGE_SVG);
    ///
    /// assert_eq!(svg.suffix(), Some(mime::XML));
    /// assert_eq!(svg.suffix().unwrap(), "xml");
    ///
    ///
    /// let any = mime::STAR_STAR;
    ///
    /// assert_eq!(any.suffix(), None);
    /// ```
    #[inline]
    pub fn suffix(&self) -> Option<&str> {
        self.mime.suffix()
    }

    /// Checks if this `MediaRange` matches a specific `MediaType`.
    ///
    /// # Example
    ///
    /// ```
    /// let images = mime::IMAGE_STAR;
    ///
    /// assert!(images.matches(&mime::IMAGE_JPEG));
    /// assert!(images.matches(&mime::IMAGE_PNG));
    ///
    /// assert!(!images.matches(&mime::TEXT_PLAIN));
    /// ```
    pub fn matches(&self, mt: &MediaType) -> bool {
        let type_ = self.type_();

        if type_ == crate::STAR {
            // sanity check there's no `*/plain` or whatever
            debug_assert_eq!(self.subtype(), crate::STAR);

            return self.matches_params(mt);
        }

        if type_ != mt.type_() {
            return false;
        }

        let subtype = self.subtype();

        if subtype == crate::STAR {
            return self.matches_params(mt);
        }

        if subtype != mt.subtype() {
            return false;
        }

        // type and subtype are the same, last thing to do is check
        // that the MediaType contains all this range's parameters...
        self.matches_params(mt)
    }

    fn matches_params(&self, mt: &MediaType) -> bool {
        for (name, value) in self.params() {
            if name != "q" && mt.param(name) != Some(value) {
                return false;
            }
        }

        true
    }

    /// Look up a parameter by name.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::MediaRange::from(mime::TEXT_PLAIN_UTF_8);
    ///
    /// assert_eq!(range.param(mime::CHARSET), Some(mime::UTF_8));
    /// assert_eq!(range.param("charset").unwrap(), "utf-8");
    /// assert_eq!(range.param("boundary"), None);
    /// ```
    pub fn param<'a>(&'a self, attr: &str) -> Option<Value<'a>> {
        self.params().find(|e| attr == e.0).map(|e| e.1)
    }

    /// Returns an iterator over the parameters.
    ///
    /// # Example
    ///
    /// ```
    /// let pkcs7 = mime::MediaRange::parse(
    ///     "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"
    /// ).unwrap();
    ///
    /// let mut params = pkcs7.params();
    ///
    /// let (name, value) = params.next().unwrap();
    /// assert_eq!(name, "smime-type");
    /// assert_eq!(value, "enveloped-data");
    ///
    /// let (name, value) = params.next().unwrap();
    /// assert_eq!(name, "name");
    /// assert_eq!(value, "smime.p7m");
    ///
    /// assert!(params.next().is_none());
    /// ```
    #[inline]
    pub fn params(&self) -> impl Iterator<Item = (&str, Value)> {
        self.mime.params().map(|(n, v)| {
            let value = Value::new(v).for_name(n);
            (n, value)
        })
    }

    /// Returns true if the media type has at last one parameter.
    ///
    /// # Example
    ///
    /// ```
    /// let plain_text: mime::MediaType = "text/plain".parse().unwrap();
    /// assert_eq!(plain_text.has_params(), false);
    ///
    /// let plain_text_utf8: mime::MediaType = "text/plain; charset=utf-8".parse().unwrap();
    /// assert_eq!(plain_text_utf8.has_params(), true);
    /// ```
    #[inline]
    pub fn has_params(&self) -> bool {
        self.mime.has_params()
    }

    #[cfg(test)]
    pub(super) fn test_assert_asterisks(&self) {
        // asterisks are allowed in MediaRange constants
    }
}

/// Any `MediaType` can freely be a `MediaRange`.
///
/// # Example
///
/// ```
/// // If we only supported `text/plain`:
/// let range = mime::MediaRange::from(mime::TEXT_PLAIN);
/// ```
impl From<MediaType> for MediaRange {
    fn from(mt: MediaType) -> MediaRange {
        MediaRange {
            mime: mt.mime,
        }
    }
}

impl PartialEq<str> for MediaRange {
    fn eq(&self, s: &str) -> bool {
        self.mime.eq_str(s)
    }
}

impl<'a> PartialEq<&'a str> for MediaRange {
    #[inline]
    fn eq(&self, s: & &'a str) -> bool {
        self == *s
    }
}

impl<'a> PartialEq<MediaRange> for &'a str {
    #[inline]
    fn eq(&self, mr: &MediaRange) -> bool {
        mr == self
    }
}

impl PartialEq<MediaRange> for str {
    #[inline]
    fn eq(&self, mr: &MediaRange) -> bool {
        mr == self
    }
}

impl FromStr for MediaRange {
    type Err = InvalidMime;

    fn from_str(s: &str) -> Result<MediaRange, Self::Err> {
        MediaRange::parse(s)
    }
}

impl AsRef<str> for MediaRange {
    fn as_ref(&self) -> &str {
        self.mime.as_ref()
    }
}

impl fmt::Debug for MediaRange {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.mime, f)
    }
}

impl fmt::Display for MediaRange {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.mime, f)
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn media_range_from_str() {
        // exact types
        assert_eq!(MediaRange::parse("text/plain").unwrap(), MediaRange::from(TEXT_PLAIN));

        // stars
        let any = "*/*".parse::<MediaRange>().unwrap();
        assert_eq!(any, "*/*");
        assert_eq!(any, STAR_STAR);
        assert_eq!("image/*".parse::<MediaRange>().unwrap(), "image/*");
        assert_eq!("text/*; charset=utf-8".parse::<MediaRange>().unwrap(), "text/*; charset=utf-8");

        // bad stars
        MediaRange::parse("text/*plain").unwrap_err();
    }

    #[test]
    fn media_range_matches() {
        assert!(STAR_STAR.matches(&TEXT_PLAIN), "*/* matches everything");

        assert!(TEXT_STAR.matches(&TEXT_PLAIN), "text/* matches text/plain");
        assert!(TEXT_STAR.matches(&TEXT_HTML), "text/* matches text/html");
        assert!(TEXT_STAR.matches(&TEXT_HTML_UTF_8), "text/* matches text/html; charset=utf-8");

        assert!(!TEXT_STAR.matches(&IMAGE_GIF), "text/* doesn't match image/gif");
    }

    #[test]
    fn media_range_matches_params() {
        let text_any_utf8 = MediaRange::parse("text/*; charset=utf-8").unwrap();

        assert!(text_any_utf8.matches(&TEXT_PLAIN_UTF_8));
        assert!(text_any_utf8.matches(&TEXT_HTML_UTF_8));

        assert!(!text_any_utf8.matches(&TEXT_HTML));

        let many_params = MediaType::parse("text/plain; charset=utf-8; foo=bar").unwrap();
        assert!(text_any_utf8.matches(&many_params));
    }

    #[test]
    fn media_range_matches_skips_q() {
        let range = MediaRange::parse("text/*; q=0.8").unwrap();

        assert!(range.matches(&TEXT_PLAIN_UTF_8));
        assert!(range.matches(&TEXT_HTML_UTF_8));

        let range = MediaRange::parse("text/*; charset=utf-8; q=0.8").unwrap();

        assert!(range.matches(&TEXT_PLAIN_UTF_8));
        assert!(range.matches(&TEXT_HTML_UTF_8));
        assert!(!range.matches(&TEXT_HTML));
    }
}

<commit_msg>range: ensure plain media matches with parametrized form (#104)<commit_after>use std::fmt;
use std::str::FromStr;

use mime_parse::{Mime, Parse};

use crate::{InvalidMime, MediaType, Value};

/// A parsed media range used to match media types.
///
/// Commonly found in the HTTP `Accept` header, these are used for agents
/// to indicate general classes of content that they can understand.
///
/// # Example
///
/// ```
/// use mime::MediaRange;
///
/// // Suppose this was parsed from an `Accept` header
/// let range = MediaRange::parse("text/*").unwrap();
///
/// // The formats of the resource that we have:
/// let formats = vec![
///     mime::APPLICATION_JSON,
///     mime::TEXT_PLAIN_UTF_8,
///     mime::TEXT_HTML,
/// ];
///
/// for format in &formats {
///     if range.matches(format) {
///         // This should print for the plain and HTML text...
///         println!("We could send in {:?} format!", format);
///     }
/// }
/// ```
#[derive(Clone, PartialEq)]
pub struct MediaRange {
    pub(super) mime: Mime,
}

impl MediaRange {
    /// Parse a string as a `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::MediaRange::parse("*/*").unwrap();
    /// assert_eq!(range, mime::STAR_STAR);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if the source is not a valid media range.
    #[inline]
    pub fn parse(source: impl Parse) -> Result<Self, InvalidMime> {
        mime_parse::parse(source, mime_parse::CanRange::Yes)
            .map(|mime| MediaRange { mime })
            .map_err(|e| InvalidMime { inner: e })
    }

    /// Get the top level media type for this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::TEXT_STAR;
    /// assert_eq!(range.type_(), "text");
    /// assert_eq!(range.type_(), mime::TEXT);
    /// ```
    #[inline]
    pub fn type_(&self) -> &str {
        self.mime.type_()
    }

    /// Get the subtype of this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::TEXT_STAR;
    ///
    /// assert_eq!(range.subtype(), "*");
    /// assert_eq!(range.subtype(), mime::STAR);
    ///
    /// let exact = mime::MediaRange::from(mime::TEXT_PLAIN);
    /// assert_eq!(exact.subtype(), mime::PLAIN);
    /// assert_eq!(exact.subtype(), "plain");
    /// ```
    #[inline]
    pub fn subtype(&self) -> &str {
        self.mime.subtype()
    }

    /// Get an optional +suffix for this `MediaRange`.
    ///
    /// # Example
    ///
    /// ```
    /// let svg = mime::MediaRange::from(mime::IMAGE_SVG);
    ///
    /// assert_eq!(svg.suffix(), Some(mime::XML));
    /// assert_eq!(svg.suffix().unwrap(), "xml");
    ///
    ///
    /// let any = mime::STAR_STAR;
    ///
    /// assert_eq!(any.suffix(), None);
    /// ```
    #[inline]
    pub fn suffix(&self) -> Option<&str> {
        self.mime.suffix()
    }

    /// Checks if this `MediaRange` matches a specific `MediaType`.
    ///
    /// # Example
    ///
    /// ```
    /// let images = mime::IMAGE_STAR;
    ///
    /// assert!(images.matches(&mime::IMAGE_JPEG));
    /// assert!(images.matches(&mime::IMAGE_PNG));
    ///
    /// assert!(!images.matches(&mime::TEXT_PLAIN));
    /// ```
    pub fn matches(&self, mt: &MediaType) -> bool {
        let type_ = self.type_();

        if type_ == crate::STAR {
            // sanity check there's no `*/plain` or whatever
            debug_assert_eq!(self.subtype(), crate::STAR);

            return self.matches_params(mt);
        }

        if type_ != mt.type_() {
            return false;
        }

        let subtype = self.subtype();

        if subtype == crate::STAR {
            return self.matches_params(mt);
        }

        if subtype != mt.subtype() {
            return false;
        }

        // type and subtype are the same, last thing to do is check
        // that the MediaType contains all this range's parameters...
        self.matches_params(mt)
    }

    fn matches_params(&self, mt: &MediaType) -> bool {
        for (name, value) in self.params() {
            if name != "q" && mt.param(name) != Some(value) {
                return false;
            }
        }

        true
    }

    /// Look up a parameter by name.
    ///
    /// # Example
    ///
    /// ```
    /// let range = mime::MediaRange::from(mime::TEXT_PLAIN_UTF_8);
    ///
    /// assert_eq!(range.param(mime::CHARSET), Some(mime::UTF_8));
    /// assert_eq!(range.param("charset").unwrap(), "utf-8");
    /// assert_eq!(range.param("boundary"), None);
    /// ```
    pub fn param<'a>(&'a self, attr: &str) -> Option<Value<'a>> {
        self.params().find(|e| attr == e.0).map(|e| e.1)
    }

    /// Returns an iterator over the parameters.
    ///
    /// # Example
    ///
    /// ```
    /// let pkcs7 = mime::MediaRange::parse(
    ///     "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"
    /// ).unwrap();
    ///
    /// let mut params = pkcs7.params();
    ///
    /// let (name, value) = params.next().unwrap();
    /// assert_eq!(name, "smime-type");
    /// assert_eq!(value, "enveloped-data");
    ///
    /// let (name, value) = params.next().unwrap();
    /// assert_eq!(name, "name");
    /// assert_eq!(value, "smime.p7m");
    ///
    /// assert!(params.next().is_none());
    /// ```
    #[inline]
    pub fn params(&self) -> impl Iterator<Item = (&str, Value)> {
        self.mime.params().map(|(n, v)| {
            let value = Value::new(v).for_name(n);
            (n, value)
        })
    }

    /// Returns true if the media type has at last one parameter.
    ///
    /// # Example
    ///
    /// ```
    /// let plain_text: mime::MediaType = "text/plain".parse().unwrap();
    /// assert_eq!(plain_text.has_params(), false);
    ///
    /// let plain_text_utf8: mime::MediaType = "text/plain; charset=utf-8".parse().unwrap();
    /// assert_eq!(plain_text_utf8.has_params(), true);
    /// ```
    #[inline]
    pub fn has_params(&self) -> bool {
        self.mime.has_params()
    }

    #[cfg(test)]
    pub(super) fn test_assert_asterisks(&self) {
        // asterisks are allowed in MediaRange constants
    }
}

/// Any `MediaType` can freely be a `MediaRange`.
///
/// # Example
///
/// ```
/// // If we only supported `text/plain`:
/// let range = mime::MediaRange::from(mime::TEXT_PLAIN);
/// ```
impl From<MediaType> for MediaRange {
    fn from(mt: MediaType) -> MediaRange {
        MediaRange {
            mime: mt.mime,
        }
    }
}

impl PartialEq<str> for MediaRange {
    fn eq(&self, s: &str) -> bool {
        self.mime.eq_str(s)
    }
}

impl<'a> PartialEq<&'a str> for MediaRange {
    #[inline]
    fn eq(&self, s: & &'a str) -> bool {
        self == *s
    }
}

impl<'a> PartialEq<MediaRange> for &'a str {
    #[inline]
    fn eq(&self, mr: &MediaRange) -> bool {
        mr == self
    }
}

impl PartialEq<MediaRange> for str {
    #[inline]
    fn eq(&self, mr: &MediaRange) -> bool {
        mr == self
    }
}

impl FromStr for MediaRange {
    type Err = InvalidMime;

    fn from_str(s: &str) -> Result<MediaRange, Self::Err> {
        MediaRange::parse(s)
    }
}

impl AsRef<str> for MediaRange {
    fn as_ref(&self) -> &str {
        self.mime.as_ref()
    }
}

impl fmt::Debug for MediaRange {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.mime, f)
    }
}

impl fmt::Display for MediaRange {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.mime, f)
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn media_range_from_str() {
        // exact types
        assert_eq!(MediaRange::parse("text/plain").unwrap(), MediaRange::from(TEXT_PLAIN));

        // stars
        let any = "*/*".parse::<MediaRange>().unwrap();
        assert_eq!(any, "*/*");
        assert_eq!(any, STAR_STAR);
        assert_eq!("image/*".parse::<MediaRange>().unwrap(), "image/*");
        assert_eq!("text/*; charset=utf-8".parse::<MediaRange>().unwrap(), "text/*; charset=utf-8");

        // bad stars
        MediaRange::parse("text/*plain").unwrap_err();
    }

    #[test]
    fn media_range_matches() {
        assert!(STAR_STAR.matches(&TEXT_PLAIN), "*/* matches everything");

        assert!(TEXT_STAR.matches(&TEXT_PLAIN), "text/* matches text/plain");
        assert!(TEXT_STAR.matches(&TEXT_HTML), "text/* matches text/html");
        assert!(TEXT_STAR.matches(&TEXT_HTML_UTF_8), "text/* matches text/html; charset=utf-8");

        assert!(!TEXT_STAR.matches(&IMAGE_GIF), "text/* doesn't match image/gif");
    }

    #[test]
    fn media_range_matches_params() {
        let text_any_utf8 = MediaRange::parse("text/*; charset=utf-8").unwrap();

        assert!(text_any_utf8.matches(&TEXT_PLAIN_UTF_8));
        assert!(text_any_utf8.matches(&TEXT_HTML_UTF_8));

        assert!(!text_any_utf8.matches(&TEXT_HTML));

        let many_params = MediaType::parse("text/plain; charset=utf-8; foo=bar").unwrap();
        assert!(text_any_utf8.matches(&many_params));

        let text_plain = MediaRange::parse("text/plain").unwrap();
        assert!(text_plain.matches(&many_params));
    }

    #[test]
    fn media_range_matches_skips_q() {
        let range = MediaRange::parse("text/*; q=0.8").unwrap();

        assert!(range.matches(&TEXT_PLAIN_UTF_8));
        assert!(range.matches(&TEXT_HTML_UTF_8));

        let range = MediaRange::parse("text/*; charset=utf-8; q=0.8").unwrap();

        assert!(range.matches(&TEXT_PLAIN_UTF_8));
        assert!(range.matches(&TEXT_HTML_UTF_8));
        assert!(!range.matches(&TEXT_HTML));
    }
}

<|endoftext|>


<commit_before>use std::fmt;

use std::rc::Rc;

pub struct SList<T> {
    head: Rc<Node<T>>
}

impl<T: Clone> SList<T> {
    pub fn head(obj: T) -> SList<T> {
        SList {
            head: Rc::new(Node {
                next: None,
                value: obj,
            })
        }
    }

    pub fn plus(&self, obj: T) -> SList<T> {
        SList {
            head: Rc::new(Node {
                next: Some(self.head.clone()),
                value: obj
            })
        }
    }

    pub fn inner(&self) -> &T {
        &self.head.value
    }

    pub fn to_vec(&self) -> Vec<T> {
        let mut ret = Vec::new();
        let mut val = &self.head;
        loop {
            ret.push(val.value.clone());
            if let Some(ref next) = val.next {
                val = next;
            } else {
                break;
            }
        }
        ret.reverse();
        ret
    }
}

impl<T: fmt::Display> fmt::Display for SList<T>
where T: Clone + fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.to_vec())
    }
}

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}
<commit_msg>replace nice to_vec with iterator based solution<commit_after>use std::fmt;

use std::rc::Rc;

pub struct SList<T> {
    head: Rc<Node<T>>
}

impl<T: Clone> SList<T> {
    pub fn head(obj: T) -> SList<T> {
        SList {
            head: Rc::new(Node {
                next: None,
                value: obj,
            })
        }
    }

    pub fn plus(&self, obj: T) -> SList<T> {
        SList {
            head: Rc::new(Node {
                next: Some(self.head.clone()),
                value: obj
            })
        }
    }

    pub fn inner(&self) -> &T {
        &self.head.value
    }

    pub fn to_vec(&self) -> Vec<T> {
        let mut ret: Vec<T> = self.iter().collect();
        ret.reverse();
        ret
    }

    pub fn iter(&self) -> SListIter<T> {
        SListIter {
            next: Some(self.head.clone())
        }
    }
}

pub struct SListIter<T> {
    next: Option<Rc<Node<T>>>,
}

impl<T: Clone> Iterator for SListIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.next.is_none() {
            return None;
        }
        let list = self.next.as_ref().unwrap().clone();
        self.next = list.next.clone();
        Some(list.value.clone())
    }
}

impl<T: fmt::Display> fmt::Display for SList<T>
where T: Clone + fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.to_vec())
    }
}

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}
<|endoftext|>


<commit_before>use cgmath::{
    Angle as _, EuclideanSpace as _, InnerSpace as _, Rotation as _, Rotation3 as _, Transform as _,
};
use std::ops::Range;

pub type Transform = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

#[derive(Copy, Clone)]
pub enum Projection {
    Ortho {
        p: cgmath::Ortho<f32>,
        original: (u16, u16),
    },
    Perspective(cgmath::PerspectiveFov<f32>),
}

impl Projection {
    pub fn ortho(w: u16, h: u16, depth: Range<f32>) -> Self {
        Projection::Ortho {
            p: cgmath::Ortho {
                left: -0.5 * w as f32,
                right: 0.5 * w as f32,
                top: -0.5 * h as f32,
                bottom: 0.5 * h as f32,
                near: depth.start,
                far: depth.end,
            },
            original: (w, h),
        }
    }

    pub fn update(&mut self, w: u16, h: u16) {
        match *self {
            Projection::Ortho {
                ref mut p,
                ref mut original,
            } => {
                let scale_x = w as f32 / original.0 as f32;
                let scale_y = h as f32 / original.1 as f32;
                let center_x = 0.5 * p.left + 0.5 * p.right;
                let center_y = 0.5 * p.top + 0.5 * p.bottom;
                *original = (w, h);
                p.left = center_x - scale_x * (center_x - p.left);
                p.right = center_x - scale_x * (center_x - p.right);
                p.top = center_y - scale_y * (center_y - p.top);
                p.bottom = center_y - scale_y * (center_y - p.bottom);
            }
            Projection::Perspective(ref mut p) => {
                p.aspect = w as f32 / h as f32;
            }
        }
    }

    pub fn to_matrix(&self) -> cgmath::Matrix4<f32> {
        match *self {
            Projection::Ortho { p, .. } => p.into(),
            Projection::Perspective(p) => p.into(),
        }
    }
}

#[derive(Copy, Clone)]
pub struct Camera {
    pub loc: cgmath::Vector3<f32>,
    pub rot: cgmath::Quaternion<f32>,
    // this non-uniform scale is used to make the camera left-handed
    pub scale: cgmath::Vector3<f32>,
    pub proj: Projection,
}

#[derive(Debug, Copy, Clone)]
pub struct Follow {
    pub angle_x: cgmath::Deg<f32>,
    pub offset: cgmath::Vector3<f32>,
    pub speed: f32,
}

#[derive(Copy, Clone)]
pub struct Direction {
    pub view: cgmath::Vector3<f32>,
    pub height: f32,
}

pub fn compute_twist(
    quat: cgmath::Quaternion<f32>,
    direction: cgmath::Vector3<f32>,
) -> cgmath::Quaternion<f32> {
    let p = quat.v.project_on(direction);
    cgmath::Quaternion::from_sv(quat.s, p).normalize()
}

impl Camera {
    fn _scale_vec(&self, vec: cgmath::Vector3<f32>) -> cgmath::Vector3<f32> {
        cgmath::Vector3::new(
            self.scale.x * vec.x,
            self.scale.y * vec.y,
            self.scale.z * vec.z,
        )
    }

    pub fn dir(&self) -> cgmath::Vector3<f32> {
        self.rot * -cgmath::Vector3::unit_z()
    }

    pub fn depth_range(&self) -> Range<f32> {
        match self.proj {
            Projection::Ortho { p, .. } => p.near..p.far,
            Projection::Perspective(p) => p.near..p.far,
        }
    }

    fn get_proj_matrix(&self) -> cgmath::Matrix4<f32> {
        let mut proj = self.proj.to_matrix();
        // convert from GL's depth of [-1,1] to wgpu/gfx-rs [0,1]
        proj.x.z = 0.5 * (proj.x.z + proj.x.w);
        proj.y.z = 0.5 * (proj.y.z + proj.y.w);
        proj.z.z = 0.5 * (proj.z.z + proj.z.w);
        proj.w.z = 0.5 * (proj.w.z + proj.w.w);
        proj
    }

    fn view_transform(&self) -> Transform {
        cgmath::Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        }
    }

    fn scale_matrix(&self) -> cgmath::Matrix4<f32> {
        cgmath::Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z)
    }

    pub fn get_view_proj(&self) -> cgmath::Matrix4<f32> {
        let view = self.view_transform();
        let view_mx = cgmath::Matrix4::from(view.inverse_transform().unwrap());
        self.get_proj_matrix() * self.scale_matrix() * view_mx
    }

    fn intersect_ray_height(&self, dir: cgmath::Vector3<f32>, height: f32) -> cgmath::Point3<f32> {
        let t_raw = (height - self.loc.z) / dir.z;
        let range = self.depth_range();
        let t = range.start.max(t_raw).min(range.end);
        cgmath::Point3::from_vec(self.loc) + t * dir
    }

    pub fn intersect_height(&self, height: f32) -> cgmath::Point3<f32> {
        let dir = self.dir();
        self.intersect_ray_height(dir, height)
    }

    pub fn visible_bounds_at(&self, height: f32) -> Range<cgmath::Vector2<f32>> {
        let center = self.intersect_height(height).to_vec().truncate();
        let mut bounds = center..center;

        let proj = self.get_proj_matrix();
        let view = self.view_transform();
        let mx =
            cgmath::Matrix4::from(view) * self.scale_matrix() * proj.inverse_transform().unwrap();
        // Scale vectors in a way that makes their Z footprint to be -1 in local space.
        let scaler = 1.0 / self.depth_range().end;
        let ndc_points = [
            cgmath::vec2(-1.0, -1.0),
            cgmath::vec2(1.0, -1.0),
            cgmath::vec2(1.0, 1.0),
            cgmath::vec2(-1.0, 1.0),
        ];
        for ndc in &ndc_points {
            let wp = cgmath::Point3::from_homogeneous(mx * cgmath::vec4(ndc.x, ndc.y, 1.0, 1.0));
            let pt = if wp.z < self.loc.z {
                let dir = scaler * (wp - cgmath::Point3::from_vec(self.loc));
                self.intersect_ray_height(dir, height)
            } else {
                wp
            };
            bounds.start.x = bounds.start.x.min(pt.x);
            bounds.start.y = bounds.start.y.min(pt.y);
            bounds.end.x = bounds.end.x.max(pt.x);
            bounds.end.y = bounds.end.y.max(pt.y);
        }
        bounds
    }

    pub fn visible_bounds(&self) -> Range<cgmath::Vector2<f32>> {
        let lo = self.visible_bounds_at(0.0);
        let min = cgmath::vec2(self.loc.x.min(lo.start.x), self.loc.y.min(lo.start.y));
        let max = cgmath::vec2(self.loc.x.max(lo.end.x), self.loc.y.max(lo.end.y));
        min..max
    }

    pub fn bound_points(&self, height: f32) -> [cgmath::Point3<f32>; 4] {
        let vb = self.visible_bounds_at(height);
        [
            cgmath::Point3::new(vb.start.x, vb.start.y, height),
            cgmath::Point3::new(vb.end.x, vb.start.y, height),
            cgmath::Point3::new(vb.end.x, vb.end.y, height),
            cgmath::Point3::new(vb.start.x, vb.end.y, height),
        ]
    }

    pub fn follow(&mut self, target: &Transform, dt: f32, follow: &Follow) {
        let k = (dt * -follow.speed).exp();

        // Determine the Z axis rotation around the target
        let swing = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), follow.angle_x);
        let is_up = target.rot.rotate_vector(cgmath::Vector3::unit_z()).z >= 0.0;
        let twist = compute_twist(
            target.rot,
            if is_up {
                cgmath::Vector3::unit_z()
            } else {
                -cgmath::Vector3::unit_z()
            },
        );
        let patch = cgmath::Quaternion::from_axis_angle(
            cgmath::Vector3::unit_z(),
            cgmath::Deg::turn_div_2(),
        );
        let rotation = patch * twist * swing;
        self.rot = (rotation * (1.0 - k) + self.rot * k).normalize();

        let location = target.disp + (patch * twist).rotate_vector(follow.offset);
        self.loc = location * (1.0 - k) + self.loc * k;
    }

    pub fn look_by(&mut self, target: &Transform, dir: &Direction) {
        debug_assert!(dir.view.z < 0.0);
        let k = (target.disp.z - self.loc.z) / -dir.view.z;
        self.loc = target.disp + dir.view * k;
        //self.rot = cgmath::Quaternion::look_at(dir.view, cgmath::Vector3::unit_y()).invert();
        self.rot =
            cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), cgmath::Deg(30.0));
    }

    pub fn focus_on(&mut self, target: &Transform) {
        use cgmath::Angle;
        self.loc = target.disp + cgmath::vec3(0.0, -64.0, 40.0);
        self.rot = cgmath::Quaternion::from_axis_angle(
            cgmath::Vector3::unit_x(),
            cgmath::Rad::turn_div_6(),
        );
    }

    pub fn rotate_focus(
        &mut self,
        target: &Transform,
        hor: cgmath::Rad<f32>,
        ver: cgmath::Rad<f32>,
    ) {
        use cgmath::{Decomposed, One, Zero};
        let mut view = Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        };
        // old mv: inv(view) * model
        if hor.0 != 0.0 {
            // inv(new) = inv(view) * post * mid * pre
            // new = pre^ * mid^ post^ * view = post * mid^ * pre * view
            let pre = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::one(),
                disp: -target.disp,
            };
            let post = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), hor),
                disp: target.disp,
            };
            view = post.concat(&pre.concat(&view));
        }
        if ver.0 != 0.0 {
            // inv(new) * model = inv(view) * model * mid
            // model^ * new = mid^ * model^ * view
            // new = model * mid^ * model^ * view
            let target_inv = target.inverse_transform().unwrap();
            let axis_local = target_inv.rot * self.rot * cgmath::Vector3::unit_x();
            let mid = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::from_axis_angle(axis_local, -ver),
                disp: cgmath::Vector3::zero(),
            };
            view = target.concat(&mid.concat(&target_inv.concat(&view)));
        }
        self.loc = view.disp;
        self.rot = view.rot;
    }

    pub fn front_face(&self) -> wgpu::FrontFace {
        if self.scale.x * self.scale.y > 0.0 {
            wgpu::FrontFace::Cw
        } else {
            wgpu::FrontFace::Ccw
        }
    }
}
<commit_msg>Refactor camera rotation based on Y direction<commit_after>use cgmath::{Angle as _, EuclideanSpace as _, Rotation as _, Rotation3 as _, Transform as _};
use std::ops::Range;

pub type Transform = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

#[derive(Copy, Clone)]
pub enum Projection {
    Ortho {
        p: cgmath::Ortho<f32>,
        original: (u16, u16),
    },
    Perspective(cgmath::PerspectiveFov<f32>),
}

impl Projection {
    pub fn ortho(w: u16, h: u16, depth: Range<f32>) -> Self {
        Projection::Ortho {
            p: cgmath::Ortho {
                left: -0.5 * w as f32,
                right: 0.5 * w as f32,
                top: -0.5 * h as f32,
                bottom: 0.5 * h as f32,
                near: depth.start,
                far: depth.end,
            },
            original: (w, h),
        }
    }

    pub fn update(&mut self, w: u16, h: u16) {
        match *self {
            Projection::Ortho {
                ref mut p,
                ref mut original,
            } => {
                let scale_x = w as f32 / original.0 as f32;
                let scale_y = h as f32 / original.1 as f32;
                let center_x = 0.5 * p.left + 0.5 * p.right;
                let center_y = 0.5 * p.top + 0.5 * p.bottom;
                *original = (w, h);
                p.left = center_x - scale_x * (center_x - p.left);
                p.right = center_x - scale_x * (center_x - p.right);
                p.top = center_y - scale_y * (center_y - p.top);
                p.bottom = center_y - scale_y * (center_y - p.bottom);
            }
            Projection::Perspective(ref mut p) => {
                p.aspect = w as f32 / h as f32;
            }
        }
    }

    pub fn to_matrix(&self) -> cgmath::Matrix4<f32> {
        match *self {
            Projection::Ortho { p, .. } => p.into(),
            Projection::Perspective(p) => p.into(),
        }
    }
}

#[derive(Copy, Clone)]
pub struct Camera {
    pub loc: cgmath::Vector3<f32>,
    pub rot: cgmath::Quaternion<f32>,
    // this non-uniform scale is used to make the camera left-handed
    pub scale: cgmath::Vector3<f32>,
    pub proj: Projection,
}

#[derive(Debug, Copy, Clone)]
pub struct Follow {
    pub angle_x: cgmath::Deg<f32>,
    pub offset: cgmath::Vector3<f32>,
    pub speed: f32,
}

#[derive(Copy, Clone)]
pub struct Direction {
    pub view: cgmath::Vector3<f32>,
    pub height: f32,
}

impl Camera {
    fn _scale_vec(&self, vec: cgmath::Vector3<f32>) -> cgmath::Vector3<f32> {
        cgmath::Vector3::new(
            self.scale.x * vec.x,
            self.scale.y * vec.y,
            self.scale.z * vec.z,
        )
    }

    pub fn dir(&self) -> cgmath::Vector3<f32> {
        self.rot * -cgmath::Vector3::unit_z()
    }

    pub fn depth_range(&self) -> Range<f32> {
        match self.proj {
            Projection::Ortho { p, .. } => p.near..p.far,
            Projection::Perspective(p) => p.near..p.far,
        }
    }

    fn get_proj_matrix(&self) -> cgmath::Matrix4<f32> {
        let mut proj = self.proj.to_matrix();
        // convert from GL's depth of [-1,1] to wgpu/gfx-rs [0,1]
        proj.x.z = 0.5 * (proj.x.z + proj.x.w);
        proj.y.z = 0.5 * (proj.y.z + proj.y.w);
        proj.z.z = 0.5 * (proj.z.z + proj.z.w);
        proj.w.z = 0.5 * (proj.w.z + proj.w.w);
        proj
    }

    fn view_transform(&self) -> Transform {
        cgmath::Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        }
    }

    fn scale_matrix(&self) -> cgmath::Matrix4<f32> {
        cgmath::Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z)
    }

    pub fn get_view_proj(&self) -> cgmath::Matrix4<f32> {
        let view = self.view_transform();
        let view_mx = cgmath::Matrix4::from(view.inverse_transform().unwrap());
        self.get_proj_matrix() * self.scale_matrix() * view_mx
    }

    fn intersect_ray_height(&self, dir: cgmath::Vector3<f32>, height: f32) -> cgmath::Point3<f32> {
        let t_raw = (height - self.loc.z) / dir.z;
        let range = self.depth_range();
        let t = range.start.max(t_raw).min(range.end);
        cgmath::Point3::from_vec(self.loc) + t * dir
    }

    pub fn intersect_height(&self, height: f32) -> cgmath::Point3<f32> {
        let dir = self.dir();
        self.intersect_ray_height(dir, height)
    }

    pub fn visible_bounds_at(&self, height: f32) -> Range<cgmath::Vector2<f32>> {
        let center = self.intersect_height(height).to_vec().truncate();
        let mut bounds = center..center;

        let proj = self.get_proj_matrix();
        let view = self.view_transform();
        let mx =
            cgmath::Matrix4::from(view) * self.scale_matrix() * proj.inverse_transform().unwrap();
        // Scale vectors in a way that makes their Z footprint to be -1 in local space.
        let scaler = 1.0 / self.depth_range().end;
        let ndc_points = [
            cgmath::vec2(-1.0, -1.0),
            cgmath::vec2(1.0, -1.0),
            cgmath::vec2(1.0, 1.0),
            cgmath::vec2(-1.0, 1.0),
        ];
        for ndc in &ndc_points {
            let wp = cgmath::Point3::from_homogeneous(mx * cgmath::vec4(ndc.x, ndc.y, 1.0, 1.0));
            let pt = if wp.z < self.loc.z {
                let dir = scaler * (wp - cgmath::Point3::from_vec(self.loc));
                self.intersect_ray_height(dir, height)
            } else {
                wp
            };
            bounds.start.x = bounds.start.x.min(pt.x);
            bounds.start.y = bounds.start.y.min(pt.y);
            bounds.end.x = bounds.end.x.max(pt.x);
            bounds.end.y = bounds.end.y.max(pt.y);
        }
        bounds
    }

    pub fn visible_bounds(&self) -> Range<cgmath::Vector2<f32>> {
        let lo = self.visible_bounds_at(0.0);
        let min = cgmath::vec2(self.loc.x.min(lo.start.x), self.loc.y.min(lo.start.y));
        let max = cgmath::vec2(self.loc.x.max(lo.end.x), self.loc.y.max(lo.end.y));
        min..max
    }

    pub fn bound_points(&self, height: f32) -> [cgmath::Point3<f32>; 4] {
        let vb = self.visible_bounds_at(height);
        [
            cgmath::Point3::new(vb.start.x, vb.start.y, height),
            cgmath::Point3::new(vb.end.x, vb.start.y, height),
            cgmath::Point3::new(vb.end.x, vb.end.y, height),
            cgmath::Point3::new(vb.start.x, vb.end.y, height),
        ]
    }

    pub fn follow(&mut self, target: &Transform, dt: f32, follow: &Follow) {
        // Determine the Z axis rotation around the target
        let swing = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), follow.angle_x);
        let mut front = target.rot.rotate_vector(cgmath::Vector3::unit_y());
        front.z = 0.0;
        let twist = cgmath::Quaternion::from_arc(cgmath::Vector3::unit_y(), front, None);

        let patch = cgmath::Quaternion::from_axis_angle(
            cgmath::Vector3::unit_z(),
            cgmath::Deg::turn_div_2(),
        );
        let rotation = patch * twist * swing;

        let k = (dt * -follow.speed).exp();
        self.rot = rotation.slerp(self.rot, k);

        let location = target.disp + (patch * twist).rotate_vector(follow.offset);
        self.loc = location * (1.0 - k) + self.loc * k;
    }

    pub fn look_by(&mut self, target: &Transform, dir: &Direction) {
        debug_assert!(dir.view.z < 0.0);
        let k = (target.disp.z - self.loc.z) / -dir.view.z;
        self.loc = target.disp + dir.view * k;
        //self.rot = cgmath::Quaternion::look_at(dir.view, cgmath::Vector3::unit_y()).invert();
        self.rot =
            cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), cgmath::Deg(30.0));
    }

    pub fn focus_on(&mut self, target: &Transform) {
        use cgmath::Angle;
        self.loc = target.disp + cgmath::vec3(0.0, -64.0, 40.0);
        self.rot = cgmath::Quaternion::from_axis_angle(
            cgmath::Vector3::unit_x(),
            cgmath::Rad::turn_div_6(),
        );
    }

    pub fn rotate_focus(
        &mut self,
        target: &Transform,
        hor: cgmath::Rad<f32>,
        ver: cgmath::Rad<f32>,
    ) {
        use cgmath::{Decomposed, One, Zero};
        let mut view = Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        };
        // old mv: inv(view) * model
        if hor.0 != 0.0 {
            // inv(new) = inv(view) * post * mid * pre
            // new = pre^ * mid^ post^ * view = post * mid^ * pre * view
            let pre = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::one(),
                disp: -target.disp,
            };
            let post = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), hor),
                disp: target.disp,
            };
            view = post.concat(&pre.concat(&view));
        }
        if ver.0 != 0.0 {
            // inv(new) * model = inv(view) * model * mid
            // model^ * new = mid^ * model^ * view
            // new = model * mid^ * model^ * view
            let target_inv = target.inverse_transform().unwrap();
            let axis_local = target_inv.rot * self.rot * cgmath::Vector3::unit_x();
            let mid = Decomposed {
                scale: 1.0,
                rot: cgmath::Quaternion::from_axis_angle(axis_local, -ver),
                disp: cgmath::Vector3::zero(),
            };
            view = target.concat(&mid.concat(&target_inv.concat(&view)));
        }
        self.loc = view.disp;
        self.rot = view.rot;
    }

    pub fn front_face(&self) -> wgpu::FrontFace {
        if self.scale.x * self.scale.y > 0.0 {
            wgpu::FrontFace::Cw
        } else {
            wgpu::FrontFace::Ccw
        }
    }
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;

use linked_hash_map::LinkedHashMap;

use crate::key::Key;
use crate::repr::{Decor, InternalString, Repr};
use crate::value::DEFAULT_VALUE_DECOR;
use crate::{Item, Value};

// TODO: add method to convert a table into inline table

/// Type representing a TOML non-inline table
#[derive(Clone, Debug, Default)]
pub struct Table {
    pub(crate) items: KeyValuePairs,
    // comments/spaces before and after the header
    pub(crate) decor: Decor,
    // whether to hide an empty table
    pub(crate) implicit: bool,
    // used for putting tables back in their original order when serialising.
    // Will be None when the Table wasn't parsed from a file.
    pub(crate) position: Option<usize>,
}

impl Table {
    /// Creates an empty table.
    pub fn new() -> Self {
        Self::with_decor_and_pos(Decor::new("\n", ""), None)
    }

    pub(crate) fn with_pos(position: Option<usize>) -> Self {
        Self {
            position,
            ..Default::default()
        }
    }

    pub(crate) fn with_decor_and_pos(decor: Decor, position: Option<usize>) -> Self {
        Self {
            decor,
            position,
            ..Default::default()
        }
    }
}

impl Table {
    /// Returns an iterator over all key/value pairs, including empty.
    pub fn iter(&self) -> Iter<'_> {
        Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value)))
    }

    /// Returns an mutable iterator over all key/value pairs, including empty.
    pub fn iter_mut(&mut self) -> IterMut<'_> {
        Box::new(
            self.items
                .iter_mut()
                .map(|(key, kv)| (&key[..], &mut kv.value)),
        )
    }

    /// Returns the number of non-empty items in the table.
    pub fn len(&self) -> usize {
        self.items.iter().filter(|i| !(i.1).value.is_none()).count()
    }

    /// Returns the number of key/value pairs in the table.
    pub fn values_len(&self) -> usize {
        self.items.iter().filter(|i| (i.1).value.is_value()).count()
    }

    /// Returns true iff the table is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse.
    pub fn clear(&mut self) {
        self.items.clear()
    }

    /// Given the `key`, return a mutable reference to the value.
    /// If there is no entry associated with the given key in the table,
    /// a `Item::None` value will be inserted.
    ///
    /// To insert to table, use `entry` to return a mutable reference
    /// and set it to the appropriate value.
    pub fn entry<'a>(&'a mut self, key: &str) -> &'a mut Item {
        let key = Key::with_key(key);
        &mut self
            .items
            .entry(key.get().to_owned())
            .or_insert_with(|| TableKeyValue::new(key.repr().to_owned(), Item::None))
            .value
    }

    /// Given the `key`, return a mutable reference to the value.
    /// If there is no entry associated with the given key in the table,
    /// a `Item::None` value will be inserted.
    ///
    /// To insert to table, use `entry` to return a mutable reference
    /// and set it to the appropriate value.
    pub fn entry_format<'a>(&'a mut self, key: &Key) -> &'a mut Item {
        &mut self
            .items
            .entry(key.get().to_owned())
            .or_insert_with(|| TableKeyValue::new(key.repr().to_owned(), Item::None))
            .value
    }

    /// Returns an optional reference to an item given the key.
    pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> {
        self.items.get(key).map(|kv| &kv.value)
    }

    /// Returns an optional mutable reference to an item given the key.
    pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Item> {
        self.items.get_mut(key).map(|kv| &mut kv.value)
    }

    /// Returns true iff the table contains an item with the given key.
    pub fn contains_key(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            !kv.value.is_none()
        } else {
            false
        }
    }

    /// Returns true iff the table contains a table with the given key.
    pub fn contains_table(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_table()
        } else {
            false
        }
    }

    /// Returns true iff the table contains a value with the given key.
    pub fn contains_value(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_value()
        } else {
            false
        }
    }

    /// Returns true iff the table contains an array of tables with the given key.
    pub fn contains_array_of_tables(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_array_of_tables()
        } else {
            false
        }
    }

    /// Inserts a key-value pair into the map.
    pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option<Item> {
        let kv = TableKeyValue::new(key.repr().to_owned(), item);
        self.items
            .insert(key.get().to_owned(), kv)
            .map(|kv| kv.value)
    }

    /// Removes an item given the key.
    pub fn remove(&mut self, key: &str) -> Option<Item> {
        self.items.remove(key).map(|kv| kv.value)
    }
}

impl Table {
    /// If a table has no key/value pairs and implicit, it will not be displayed.
    ///
    /// # Examples
    ///
    /// ```notrust
    /// [target."x86_64/windows.json".dependencies]
    /// ```
    ///
    /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit.
    ///
    /// ```
    /// use toml_edit::Document;
    /// let mut doc = "[a]\n[a.b]\n".parse::<Document>().expect("invalid toml");
    ///
    /// doc["a"].as_table_mut().unwrap().set_implicit(true);
    /// assert_eq!(doc.to_string(), "[a.b]\n");
    /// ```
    pub fn set_implicit(&mut self, implicit: bool) {
        self.implicit = implicit;
    }

    /// Sorts Key/Value Pairs of the table.
    ///
    /// Doesn't affect subtables or subarrays.
    pub fn sort_values(&mut self) {
        sort_key_value_pairs(&mut self.items);
    }

    /// Auto formats the table.
    pub fn fmt(&mut self) {
        decorate_table(self);
    }

    /// Returns the decor associated with a given key of the table.
    pub fn decor(&self, key: &str) -> Option<&Decor> {
        self.items.get(key).map(|kv| &kv.key_decor)
    }

    /// Sets the position of the `Table` within the `Document`.
    ///
    /// Setting the position of a table will only affect output when
    /// `Document::to_string_in_original_order` is used.
    pub fn set_position(&mut self, position: usize) {
        self.position = Some(position);
    }

    /// The position of the `Table` within the `Document`.
    ///
    /// Returns `None` if the `Table` was created manually (i.e. not via parsing)
    /// in which case its position is set automatically.
    pub fn position(&self) -> Option<usize> {
        self.position
    }
}

impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for Table {
    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
        for (key, value) in iter {
            let key = key.into();
            let value = Item::Value(value.into());
            let value = TableKeyValue::new(key.repr().to_owned(), value);
            self.items.insert(key.into(), value);
        }
    }
}

impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Table {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let mut table = Table::new();
        table.extend(iter);
        table
    }
}

pub(crate) type KeyValuePairs = LinkedHashMap<InternalString, TableKeyValue>;

pub(crate) fn sort_key_value_pairs(items: &mut LinkedHashMap<InternalString, TableKeyValue>) {
    let mut keys: Vec<InternalString> = items
        .iter()
        .filter_map(|i| (i.1).value.as_value().map(|_| i.0))
        .cloned()
        .collect();
    keys.sort();
    for key in keys {
        items.get_refresh(&key);
    }
}

fn decorate_table(table: &mut Table) {
    for (key_decor, value) in table
        .items
        .iter_mut()
        .filter(|&(_, ref kv)| kv.value.is_value())
        .map(|(_, kv)| (&mut kv.key_decor, kv.value.as_value_mut().unwrap()))
    {
        // `key1 = value1`
        *key_decor = Decor::new(DEFAULT_KEY_DECOR.0, DEFAULT_KEY_DECOR.1);
        value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1);
    }
}

// `key1 = value1`
pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " ");
pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("", "");

// TODO: make pub(crate)
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TableKeyValue {
    pub(crate) key_repr: Repr,
    pub(crate) key_decor: Decor,
    pub(crate) value: Item,
}

impl TableKeyValue {
    pub(crate) fn new(key_repr: Repr, value: Item) -> Self {
        TableKeyValue {
            key_repr,
            key_decor: Default::default(),
            value,
        }
    }
}

/// An iterator type over `Table`'s key/value pairs.
pub type Iter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Item)> + 'a>;
/// A mutable iterator type over `Table`'s key/value pairs.
pub type IterMut<'a> = Box<dyn Iterator<Item = (&'a str, &'a mut Item)> + 'a>;

/// This trait represents either a `Table`, or an `InlineTable`.
pub trait TableLike {
    /// Returns an iterator over key/value pairs.
    fn iter(&self) -> Iter<'_>;
    /// Returns the number of nonempty items.
    fn len(&self) -> usize {
        self.iter().filter(|&(_, v)| !v.is_none()).count()
    }
    /// Returns true iff the table is empty.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    /// Returns an optional reference to an item given the key.
    fn get<'s>(&'s self, key: &str) -> Option<&'s Item>;
    /// Returns an optional mutable reference to an item given the key.
    fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item>;
}

impl TableLike for Table {
    /// Returns an iterator over all subitems, including `Item::None`.
    fn iter(&self) -> Iter<'_> {
        self.iter()
    }
    fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
        self.get(key)
    }
    fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> {
        self.get_mut(key)
    }
}
<commit_msg>fix: Missed a default decor (#142)<commit_after>use std::iter::FromIterator;

use linked_hash_map::LinkedHashMap;

use crate::key::Key;
use crate::repr::{Decor, InternalString, Repr};
use crate::value::DEFAULT_VALUE_DECOR;
use crate::{Item, Value};

// TODO: add method to convert a table into inline table

/// Type representing a TOML non-inline table
#[derive(Clone, Debug, Default)]
pub struct Table {
    pub(crate) items: KeyValuePairs,
    // comments/spaces before and after the header
    pub(crate) decor: Decor,
    // whether to hide an empty table
    pub(crate) implicit: bool,
    // used for putting tables back in their original order when serialising.
    // Will be None when the Table wasn't parsed from a file.
    pub(crate) position: Option<usize>,
}

impl Table {
    /// Creates an empty table.
    pub fn new() -> Self {
        Default::default()
    }

    pub(crate) fn with_pos(position: Option<usize>) -> Self {
        Self {
            position,
            ..Default::default()
        }
    }

    pub(crate) fn with_decor_and_pos(decor: Decor, position: Option<usize>) -> Self {
        Self {
            decor,
            position,
            ..Default::default()
        }
    }
}

impl Table {
    /// Returns an iterator over all key/value pairs, including empty.
    pub fn iter(&self) -> Iter<'_> {
        Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value)))
    }

    /// Returns an mutable iterator over all key/value pairs, including empty.
    pub fn iter_mut(&mut self) -> IterMut<'_> {
        Box::new(
            self.items
                .iter_mut()
                .map(|(key, kv)| (&key[..], &mut kv.value)),
        )
    }

    /// Returns the number of non-empty items in the table.
    pub fn len(&self) -> usize {
        self.items.iter().filter(|i| !(i.1).value.is_none()).count()
    }

    /// Returns the number of key/value pairs in the table.
    pub fn values_len(&self) -> usize {
        self.items.iter().filter(|i| (i.1).value.is_value()).count()
    }

    /// Returns true iff the table is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse.
    pub fn clear(&mut self) {
        self.items.clear()
    }

    /// Given the `key`, return a mutable reference to the value.
    /// If there is no entry associated with the given key in the table,
    /// a `Item::None` value will be inserted.
    ///
    /// To insert to table, use `entry` to return a mutable reference
    /// and set it to the appropriate value.
    pub fn entry<'a>(&'a mut self, key: &str) -> &'a mut Item {
        let key = Key::with_key(key);
        &mut self
            .items
            .entry(key.get().to_owned())
            .or_insert_with(|| TableKeyValue::new(key.repr().to_owned(), Item::None))
            .value
    }

    /// Given the `key`, return a mutable reference to the value.
    /// If there is no entry associated with the given key in the table,
    /// a `Item::None` value will be inserted.
    ///
    /// To insert to table, use `entry` to return a mutable reference
    /// and set it to the appropriate value.
    pub fn entry_format<'a>(&'a mut self, key: &Key) -> &'a mut Item {
        &mut self
            .items
            .entry(key.get().to_owned())
            .or_insert_with(|| TableKeyValue::new(key.repr().to_owned(), Item::None))
            .value
    }

    /// Returns an optional reference to an item given the key.
    pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> {
        self.items.get(key).map(|kv| &kv.value)
    }

    /// Returns an optional mutable reference to an item given the key.
    pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Item> {
        self.items.get_mut(key).map(|kv| &mut kv.value)
    }

    /// Returns true iff the table contains an item with the given key.
    pub fn contains_key(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            !kv.value.is_none()
        } else {
            false
        }
    }

    /// Returns true iff the table contains a table with the given key.
    pub fn contains_table(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_table()
        } else {
            false
        }
    }

    /// Returns true iff the table contains a value with the given key.
    pub fn contains_value(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_value()
        } else {
            false
        }
    }

    /// Returns true iff the table contains an array of tables with the given key.
    pub fn contains_array_of_tables(&self, key: &str) -> bool {
        if let Some(kv) = self.items.get(key) {
            kv.value.is_array_of_tables()
        } else {
            false
        }
    }

    /// Inserts a key-value pair into the map.
    pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option<Item> {
        let kv = TableKeyValue::new(key.repr().to_owned(), item);
        self.items
            .insert(key.get().to_owned(), kv)
            .map(|kv| kv.value)
    }

    /// Removes an item given the key.
    pub fn remove(&mut self, key: &str) -> Option<Item> {
        self.items.remove(key).map(|kv| kv.value)
    }
}

impl Table {
    /// If a table has no key/value pairs and implicit, it will not be displayed.
    ///
    /// # Examples
    ///
    /// ```notrust
    /// [target."x86_64/windows.json".dependencies]
    /// ```
    ///
    /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit.
    ///
    /// ```
    /// use toml_edit::Document;
    /// let mut doc = "[a]\n[a.b]\n".parse::<Document>().expect("invalid toml");
    ///
    /// doc["a"].as_table_mut().unwrap().set_implicit(true);
    /// assert_eq!(doc.to_string(), "[a.b]\n");
    /// ```
    pub fn set_implicit(&mut self, implicit: bool) {
        self.implicit = implicit;
    }

    /// Sorts Key/Value Pairs of the table.
    ///
    /// Doesn't affect subtables or subarrays.
    pub fn sort_values(&mut self) {
        sort_key_value_pairs(&mut self.items);
    }

    /// Auto formats the table.
    pub fn fmt(&mut self) {
        decorate_table(self);
    }

    /// Returns the decor associated with a given key of the table.
    pub fn decor(&self, key: &str) -> Option<&Decor> {
        self.items.get(key).map(|kv| &kv.key_decor)
    }

    /// Sets the position of the `Table` within the `Document`.
    ///
    /// Setting the position of a table will only affect output when
    /// `Document::to_string_in_original_order` is used.
    pub fn set_position(&mut self, position: usize) {
        self.position = Some(position);
    }

    /// The position of the `Table` within the `Document`.
    ///
    /// Returns `None` if the `Table` was created manually (i.e. not via parsing)
    /// in which case its position is set automatically.
    pub fn position(&self) -> Option<usize> {
        self.position
    }
}

impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for Table {
    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
        for (key, value) in iter {
            let key = key.into();
            let value = Item::Value(value.into());
            let value = TableKeyValue::new(key.repr().to_owned(), value);
            self.items.insert(key.into(), value);
        }
    }
}

impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Table {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let mut table = Table::new();
        table.extend(iter);
        table
    }
}

pub(crate) type KeyValuePairs = LinkedHashMap<InternalString, TableKeyValue>;

pub(crate) fn sort_key_value_pairs(items: &mut LinkedHashMap<InternalString, TableKeyValue>) {
    let mut keys: Vec<InternalString> = items
        .iter()
        .filter_map(|i| (i.1).value.as_value().map(|_| i.0))
        .cloned()
        .collect();
    keys.sort();
    for key in keys {
        items.get_refresh(&key);
    }
}

fn decorate_table(table: &mut Table) {
    for (key_decor, value) in table
        .items
        .iter_mut()
        .filter(|&(_, ref kv)| kv.value.is_value())
        .map(|(_, kv)| (&mut kv.key_decor, kv.value.as_value_mut().unwrap()))
    {
        // `key1 = value1`
        *key_decor = Decor::new(DEFAULT_KEY_DECOR.0, DEFAULT_KEY_DECOR.1);
        value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1);
    }
}

// `key1 = value1`
pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " ");
pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("\n", "");

// TODO: make pub(crate)
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TableKeyValue {
    pub(crate) key_repr: Repr,
    pub(crate) key_decor: Decor,
    pub(crate) value: Item,
}

impl TableKeyValue {
    pub(crate) fn new(key_repr: Repr, value: Item) -> Self {
        TableKeyValue {
            key_repr,
            key_decor: Default::default(),
            value,
        }
    }
}

/// An iterator type over `Table`'s key/value pairs.
pub type Iter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Item)> + 'a>;
/// A mutable iterator type over `Table`'s key/value pairs.
pub type IterMut<'a> = Box<dyn Iterator<Item = (&'a str, &'a mut Item)> + 'a>;

/// This trait represents either a `Table`, or an `InlineTable`.
pub trait TableLike {
    /// Returns an iterator over key/value pairs.
    fn iter(&self) -> Iter<'_>;
    /// Returns the number of nonempty items.
    fn len(&self) -> usize {
        self.iter().filter(|&(_, v)| !v.is_none()).count()
    }
    /// Returns true iff the table is empty.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    /// Returns an optional reference to an item given the key.
    fn get<'s>(&'s self, key: &str) -> Option<&'s Item>;
    /// Returns an optional mutable reference to an item given the key.
    fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item>;
}

impl TableLike for Table {
    /// Returns an iterator over all subitems, including `Item::None`.
    fn iter(&self) -> Iter<'_> {
        self.iter()
    }
    fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
        self.get(key)
    }
    fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> {
        self.get_mut(key)
    }
}
<|endoftext|>


<commit_before>use super::{Event, State, Action, StateMachine, Initializer};

extern crate fern;
extern crate time;
use log;

fn conf_logger() {
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}

macro_rules! impl_state {
    ($nam:ident, $evts:ty) => {
        impl<'a> State<'a, $evts> for $nam<$evts> {
            fn handle_event(&'a mut self, evt: Event<$evts>) -> Action<'a, $evts> {
                Action::Ignore
            }
        }
    }
}

// #[test]
// fn event_enum() {
//     let events = [Event::Enter, Event::Exit, Event::User(5u8)];
//     for ev in & events[..] {
//         print!("{:?}    ",  ev);
//     }
//     println!("");
// }
//
// #[test]
// fn event_enum_complex() {
//     #[derive(Debug)]
//     enum MyEvent<T> {
//         Tere,
//         HeadAega,
//         Number(T)
//     }
//     let events = [Event::Enter, Event::Exit, Event::User(MyEvent::Tere), Event::User(MyEvent::Number(4i16))];
//     for ev in & events[..] {
//         print!("{:?}    ",  ev);
//     }
//     println!("");
// }
//
// #[test]
// fn state() {
//     struct MyState<T> {
//         _phantom: ::std::marker::PhantomData<T>
//     }
//     impl<T> Initializer for MyState<T> {
//         fn new() -> Self {
//             MyState {_phantom : ::std::marker::PhantomData}
//         }
//     }
//     impl<'a, T> State<'a, T> for MyState<T> {
//         fn handle_event(&'a mut self, evt: Event<T>) -> Action<'a, T> {
//             Action::Ignore
//         }
//     }
//     let mut st = MyState::new();
//     println!("{}", st.handle_event(Event::User(4u8)));
// }
//
// #[test]
// fn state_macro() {
//     new_state!{MyState};
//     impl<'a, T> State<'a, T> for MyState<T> {
//         fn handle_event(&'a mut self, evt: Event<T>) -> Action<'a, T> {
//             Action::Ignore
//         }
//     }
//     let mut st = MyState::new();
//     println!("{}", st.handle_event(Event::User(4u8)));
// }
// #[test]
// fn state_macro_complex() {
//     new_state!{
//         MyState {
//             tere : u8 : 5,
//             hei  : u8 : 9
//         }
//     };
//     impl<'a, T> State<'a, T> for MyState<T> {
//         fn handle_event(&'a mut self, evt: Event<T>) -> Action<'a, T> {
//             Action::Ignore
//         }
//     }
//     let mut st = MyState::new();
//     println!("{}", st.handle_event(Event::User(4u8)));
// }
// #[test]
// fn state_enum_and_struct_macro() {
//     #[derive(Debug)]
//     enum MyEvent<T> {
//         Tere,
//         HeadAega,
//         Number(T)
//     }
//     new_state!{Hei, MyEvent<u8>};
//     impl_state!(Hei, MyEvent<u8>);
//     new_state!{Hoo, MyEvent<u8>};
//     impl_state!(Hoo, MyEvent<u8>);
//     create_state_enum_and_struct!{StateEnum, StateStruct, MyEvent<u8>, (Hei, Hoo)};
// }

#[test]
fn state_machine() {
    conf_logger();
    #[derive(Debug)]
    enum MyEvent<T> {
        Tere,
        HeadAega,
        Number(T)
    }
    hsm_define_objects!(StateStruct, StateEnum, MyEvent<u8>, (Hei, Hoo));
    impl_state!(Hei, MyEvent<u8>);
    impl_state!(Hoo, MyEvent<u8>);
    let mut sm = StateMachine::<StateStruct, StateEnum, MyEvent<u8>>::new(StateEnum::Hei);
    sm.input(Event::Enter);
    let testevent = Hei::<MyEvent<u8>>::new();
    info!("{:?}", &testevent as &State<MyEvent<u8>>);
}
<commit_msg>remove tests.rs - outdated<commit_after><|endoftext|>


<commit_before>extern crate regex;
use self::regex::Regex;
use super::*;

/*
#[test]
fn parse_args_help_works() {
    assert_eq!(parse_args(vec!["-h".to_string()]), Ok(ShowHelp));
    assert_eq!(parse_args(vec!["--help".to_string()]), Ok(ShowHelp));
}

#[test]
fn parse_args_version_works() {
    assert_eq!(parse_args(vec!["-v".to_string()]), Ok(ShowVersion));
    assert_eq!(parse_args(vec!["--version".to_string()]), Ok(ShowVersion));
}

#[test]
fn parse_args_uses_default_string() {
    assert_eq!(parse_args(vec![]), Ok(RepeatString(DEFAULT_STRING.to_string())));
}

#[test]
fn parse_args_uses_arguments() {
    assert_eq!(parse_args(vec!["str".to_string()]),
               Ok(RepeatString("str".to_string())));
}

#[test]
fn parse_args_concatenates_arguments() {
    assert_eq!(parse_args(vec!["str".to_string(), "dup".to_string()]),
               Ok(RepeatString("str dup".to_string())));
}

#[test]
fn parse_args_allows_escaped_flags() {
    assert_eq!(parse_args(vec!["--".to_string(), "-h".to_string()]),
               Ok(RepeatString("-h".to_string())));
}

#[test]
fn parse_args_raises_error_on_illegal_argument() {
    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(InvalidOption(_)) => assert!(true),
        _ => unreachable!()
    }
}

#[test]
fn parse_args_error_has_message() {
    let re = Regex::new(r"Unrecognized option").unwrap();

    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(e) => assert!(re.is_match(&e.message())),
        _ => unreachable!()
    }
}
*/
#[test]
fn string_newline_terminate_works() {
    assert_eq!("word".to_string().newline_terminate(), "word\n");
    assert_eq!("myname".to_string().newline_terminate(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".to_string().fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

struct Full {
}

impl Full {
    fn new() -> Self {
        Full{}
    }
}

impl Write for Full {
    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

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

#[test]
fn write_repeat_stops_on_error() {
    assert_eq!(Full::new().write_repeat("some data".as_bytes()).kind(),
               io::ErrorKind::BrokenPipe);
}
<commit_msg>removes unused tests<commit_after>extern crate regex;
use self::regex::Regex;
use super::*;

#[test]
fn string_newline_terminate_works() {
    assert_eq!("word".with_newline(), "word\n");
    assert_eq!("myname".with_newline(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

struct Full {
}

impl Full {
    fn new() -> Self {
        Full{}
    }
}

impl Write for Full {
    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

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

#[test]
fn write_repeat_stops_on_error() {
    assert_eq!(Full::new().write_repeat("some data".as_bytes()).kind(),
               io::ErrorKind::BrokenPipe);
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use dispatcher::request::{ExternalRequest, Request};

#[derive(Clone, Copy, Debug)]
pub struct TimerEvent(pub Duration);

impl TimerEvent {
    #[allow(dead_code)]
    pub fn from_millis(ms: u64) -> TimerEvent {
        TimerEvent(Duration::from_millis(ms))
    }
}

pub struct Timer;

impl Timer {
    pub fn from_chan(duration: Duration, tx: mpsc::Sender<ExternalRequest>) {
        thread::spawn(move || {
            loop {
                thread::sleep(duration);
                if tx.send(Request::Timer(TimerEvent(duration))).is_err() {
                    break;
                }
            }
        });
    }
}
<commit_msg>Timer: simplify loop<commit_after>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use dispatcher::request::{ExternalRequest, Request};

#[derive(Clone, Copy, Debug)]
pub struct TimerEvent(pub Duration);

impl TimerEvent {
    #[allow(dead_code)]
    pub fn from_millis(ms: u64) -> TimerEvent {
        TimerEvent(Duration::from_millis(ms))
    }
}

pub struct Timer;

impl Timer {
    pub fn from_chan(duration: Duration, tx: mpsc::Sender<ExternalRequest>) {
        thread::spawn(move || {
            while let Ok(_) = tx.send(Request::Timer(TimerEvent(duration))) {
                thread::sleep(duration);
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::marker::Sized;
use serde::{Serialize};
use serde::de::DeserializeOwned;
use serde_json;
use base64::{encode_config, decode_config, URL_SAFE};

use super::errors::*;

/// trait that can be convert to/from base64 string
/// impl for `serde::Serialize`+`serde::Deserialize` are already defined
pub trait JWTStringConvertable : Sized{
    fn from_base64_str(string: &str) -> Result<Self>;
    fn to_base64_str(&self) -> Result<String>;
}

impl<T> JWTStringConvertable for T
    where T: Serialize + DeserializeOwned {
    fn from_base64_str(string: &str) -> Result<T> {
        let slice = try!(decode_config(string, URL_SAFE));
        let result = serde_json::from_slice(&slice)?;
        Ok(result)
    }

    fn to_base64_str(&self) -> Result<String> {
        let b_string = try!(serde_json::to_vec(&self));
        Ok(encode_config(&b_string,URL_SAFE))
    }
}

// some helper function to convert ecdsa signature der from/to raw format
pub fn ecdsa_der_to_raw(s: &[u8]) -> Result<Vec<u8>> {
    if s.len() < 6 {
        return Err(ErrorKind::InvalidSignature.into());
    }
    let mut result = Vec::new();
    if s[0] != 0x30 || s[2] != 0x02 {
        return Err(ErrorKind::InvalidSignature.into());
    }
    let t_len = s[1] as usize;
    if s.len() != 2 + t_len {
        return Err(ErrorKind::InvalidSignature.into());
    }
    let r_len = s[3] as usize;
    if r_len + 2 > t_len {
        return Err(ErrorKind::InvalidSignature.into());
    }

    for i in 4..4+r_len {
        if i == 4 && s[i] == 0x00 {
            continue;
        }
        result.push(s[i]);
    }
    let s_len = s[4 + r_len + 1] as usize;
    if 4 + s_len + 2 + r_len > s.len() {
        return Err(ErrorKind::InvalidSignature.into());
    }
    for i in 6+r_len..6+r_len+s_len {
        if i == 6 + r_len && s[i] == 0x00 {
            continue;
        }
        result.push(s[i]);
    }
    Ok(result)
}

pub fn ecdsa_raw_to_der(s: &[u8]) -> Result<Vec<u8>> {
    if s.len() <= 0 || s.len() % 2 != 0 {
        return Err(ErrorKind::InvalidSignature.into());
    }
    let half_len = s.len() / 2;

    let r_0 = s[0];
    let mut r_append_zero = false;
    let mut r_len = half_len;
    if r_0 > 0x7f {
        r_append_zero = true;
        r_len += 1;
    }
    let s_0 = s[half_len];
    let mut s_append_zero = false;
    let mut s_len = half_len;
    if s_0 > 0x7f {
        s_append_zero = true;
        s_len += 1;
    }

    let mut result = Vec::new();
    result.push(0x30);
    result.push(r_len as u8 + s_len as u8 + 4 );
    result.push(0x02);
    result.push(r_len as u8);
    for i in 0..half_len {
        if i == 0 && r_append_zero {
            result.push(0x00);
        }
        result.push(s[i]);
    }
    result.push(0x02);
    result.push(s_len as u8);

    for i in 0..half_len {
        if i == 0 && s_append_zero {
            result.push(0x00);
        }
        result.push(s[half_len + i]);
    }
    Ok(result)
}
<commit_msg>der <=> raw support multiple byte len<commit_after>use std::marker::Sized;
use serde::{Serialize};
use serde::de::DeserializeOwned;
use serde_json;
use base64::{encode_config, decode_config, URL_SAFE};

use super::errors::*;

/// trait that can be convert to/from base64 string
/// impl for `serde::Serialize`+`serde::Deserialize` are already defined
pub trait JWTStringConvertable : Sized{
    fn from_base64_str(string: &str) -> Result<Self>;
    fn to_base64_str(&self) -> Result<String>;
}

impl<T> JWTStringConvertable for T
    where T: Serialize + DeserializeOwned {
    fn from_base64_str(string: &str) -> Result<T> {
        let slice = try!(decode_config(string, URL_SAFE));
        let result = serde_json::from_slice(&slice)?;
        Ok(result)
    }

    fn to_base64_str(&self) -> Result<String> {
        let b_string = try!(serde_json::to_vec(&self));
        Ok(encode_config(&b_string,URL_SAFE))
    }
}

fn _safe_get_u8s(s: &[u8], i: usize) -> Result<u8> {
    s.get(i).map(|u| u.clone()).ok_or(ErrorKind::InvalidSignature.into())
}

// some helper function to convert ecdsa signature der from/to raw format
pub fn ecdsa_der_to_raw(s: &[u8]) -> Result<Vec<u8>> {
    let mut idx = 0;
    let s0 = _safe_get_u8s(s, idx)?;
    idx += 1;
    if s0 != 0x30 {
        return Err(ErrorKind::InvalidSignature.into());
    }

    let mut result = Vec::new();

    let t_len = _safe_get_u8s(s, idx)? as usize;
    idx += 1;
    if t_len > 127 { // more than one byte for len
        idx += t_len - 128;
    }

    idx += 1; // skip the 0x02

    let mut r_len = _safe_get_u8s(s, idx)? as usize;
    idx += 1;
    if r_len > 127 {
        let bit_len = r_len - 128;
        if bit_len > 4 || bit_len == 0 { // only deal with maximum 4 bytes
            return Err(ErrorKind::InvalidSignature.into());
        }
        r_len = 0x0;
        for _ in 0..bit_len {
            r_len = r_len << 8;
            r_len = r_len | (_safe_get_u8s(s, idx)? as usize);
            idx += 1;
        }
    }

    for i in 0..r_len {
        let target = _safe_get_u8s(s, idx)?;
        idx += 1;
        if i == 0 && target == 0x00 {
            continue;
        }
        result.push(target);
    }

    idx += 1; // skip the 0x02

    let mut s_len = _safe_get_u8s(s, idx)? as usize;
    idx += 1;

    if s_len > 127 {
        let bit_len = s_len - 128;
        if bit_len > 4 || bit_len == 0 { // only deal with maximum 4 bytes
            return Err(ErrorKind::InvalidSignature.into());
        }
        s_len = 0x0;
        for _ in 0..bit_len {
            s_len = s_len << 8;
            s_len = s_len | (_safe_get_u8s(s, idx)? as usize);
            idx += 1;
        }
    }

    for i in 0..s_len {
        let target = _safe_get_u8s(s, idx)?;
        idx += 1;
        if i == 0 && target == 0x00 {
            continue;
        }
        result.push(target);
    }
    Ok(result)
}

pub fn ecdsa_raw_to_der(s: &[u8]) -> Result<Vec<u8>> {
    if s.len() <= 0 || s.len() % 2 != 0 {
        return Err(ErrorKind::InvalidSignature.into());
    }
    let half_len = s.len() / 2;

    let r_0 = s[0];
    let mut r_append_zero = false;
    let mut r_len = half_len;
    if r_0 > 0x7f {
        r_append_zero = true;
        r_len += 1;
    }
    let s_0 = s[half_len];
    let mut s_append_zero = false;
    let mut s_len = half_len;
    if s_0 > 0x7f {
        s_append_zero = true;
        s_len += 1;
    }

    let mut r_len_byte = 0;
    if r_len > 127 {
        r_len_byte = 1;
        let mut temp = r_len;
        temp = temp >> 8;
        while temp > 0 {
            r_len_byte += 1;
            temp = temp >> 8;
        }
    }

    let mut s_len_byte = 0;
    if s_len > 127 {
        s_len_byte = 1;
        let mut temp = s_len;
        temp = temp >> 8;
        while temp > 0 {
            s_len_byte += 1;
            temp = temp >> 8;
        }
    }

    let t_len = 2 + 2 + r_len_byte + s_len_byte + r_len + s_len;
    let mut t_len_byte = 0;
    if t_len > 127 {
        t_len_byte = 1;
        let mut temp = t_len;
        temp = temp >> 8;
        while temp > 0 {
            t_len_byte += 1;
            temp = temp >> 8;
        }
    }

    let mut result = Vec::new();
    result.push(0x30);
    if t_len > 127 {
        result.push((t_len_byte + 128) as u8);
        while t_len_byte > 0 {
            t_len_byte -= 1;
            result.push((t_len / 2^t_len_byte) as u8);
        }
    } else {
        result.push(t_len as u8);
    }
    result.push(0x02);
    if r_len > 127 {
        result.push((r_len_byte + 128) as u8);
        while r_len_byte > 0 {
            r_len_byte -= 1;
            result.push((r_len / 2^r_len_byte) as u8);
        }
    } else {
        result.push(r_len as u8);
    }

    for i in 0..half_len {
        if i == 0 && r_append_zero {
            result.push(0x00);
        }
        result.push(s[i]);
    }
    result.push(0x02);

    if s_len > 127 {
        result.push((s_len_byte + 128) as u8);
        while s_len_byte > 0 {
            s_len_byte -= 1;
            result.push((s_len / 2^s_len_byte) as u8);
        }
    } else {
        result.push(s_len as u8);
    }

    for i in 0..half_len {
        if i == 0 && s_append_zero {
            result.push(0x00);
        }
        result.push(s[half_len + i]);
    }
    Ok(result)
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;

extern crate phf;
include!("hexkeys.rs");
// include!("hexkeys.rs");

// fn helmert(lon_vec: [&f64], lat_vec: [&f64]) -> (Vec<f64>, Vec<f64>) {
//     let t_array = Vec3::new(TX, TY, TZ);
//     let params = Mat3::new(1. + s, RZS, -RYS, -RZS, 1. + s, RXS, RYS, -RXS, 1. + s);
//     // let zeros: Vec<&f64> = vec![&1.; lon_vec.len()];
//     let test = vec![1, 2, 3, 4, 5, 6];
//     // let mut combined: Vec<&f64> = lon_vec.extend(lat_vec.iter()).collect();
//     // combined.extend(zeros.iter().cloned());
//     // let tmat = DMat::from_row_vec(3, zeros.len(), &combined);
//     let tmat = DMat::from_row_vec(3, 2, &test);
//     // build input vector of x, y, and z columns
//     // let inp = DMat::from_row_vec(3, 1, vec![lon_vec, lat_vec, h_vec]);
//     (vec![1.], vec![2.])
// }

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

/// Round Easting, Northing, and Orthometric height to the nearest millimetre
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

/// Round a float to nine decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

/// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i16, y: &i16) -> Result<(f64, f64, f64), ()> {
    // let key = format!("{:03x}{:03x}", y, x);
    let up_x = *x as u32;
    let up_y = *y as u32;
    let key = [HEXKEYS.get(&up_y).unwrap().to_string(), HEXKEYS.get(&up_x).unwrap().to_string()]
                  .concat();
    // Some or None, so convert to Result, which we can try!
    let result = try!(ostn02_lookup(&*key).ok_or(()));
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i16;
    let n_index = (*y / 1000.) as i16;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index as i32 * 1000;
    let y0 = n_index as i32 * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!

    // bottom-left grid intersection
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index), &(n_index)));
    // bottom-right
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    // top-left
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    // top-right
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = x - (x0 as f64);
    let dy = y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok(round_to_nearest_mm(se, sn, sg))

}

#[cfg(test)]
mod tests {
    use super::get_ostn_ref;
    use super::ostn02_shifts;
    use super::check;
    // use super::HEXKEYS;
    use super::phf;
    include!("hexkeys.rs");

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_failed_ostn_hashmap_retrieval() {
        // we're try!ing this in the shift calculation function, so an Err is fine
        let eastings = 999;
        let northings = 999;
        let expected = (1., 1., 1.);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    fn test_hexkeys() {
        let val = 711;
        assert_eq!(HEXKEYS[&val], "2c7");
    }

}
<commit_msg>Import all parents for testing<commit_after>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;

extern crate phf;
include!("hexkeys.rs");

// fn helmert(lon_vec: [&f64], lat_vec: [&f64]) -> (Vec<f64>, Vec<f64>) {
//     let t_array = Vec3::new(TX, TY, TZ);
//     let params = Mat3::new(1. + s, RZS, -RYS, -RZS, 1. + s, RXS, RYS, -RXS, 1. + s);
//     // let zeros: Vec<&f64> = vec![&1.; lon_vec.len()];
//     let test = vec![1, 2, 3, 4, 5, 6];
//     // let mut combined: Vec<&f64> = lon_vec.extend(lat_vec.iter()).collect();
//     // combined.extend(zeros.iter().cloned());
//     // let tmat = DMat::from_row_vec(3, zeros.len(), &combined);
//     let tmat = DMat::from_row_vec(3, 2, &test);
//     // build input vector of x, y, and z columns
//     // let inp = DMat::from_row_vec(3, 1, vec![lon_vec, lat_vec, h_vec]);
//     (vec![1.], vec![2.])
// }

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

/// Round Easting, Northing, and Orthometric height to the nearest millimetre
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

/// Round a float to nine decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

/// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i16, y: &i16) -> Result<(f64, f64, f64), ()> {
    // let key = format!("{:03x}{:03x}", y, x);
    let up_x = *x as u32;
    let up_y = *y as u32;
    let key = [HEXKEYS.get(&up_y).unwrap().to_string(), HEXKEYS.get(&up_x).unwrap().to_string()]
                  .concat();
    // Some or None, so convert to Result, which we can try!
    let result = try!(ostn02_lookup(&*key).ok_or(()));
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i16;
    let n_index = (*y / 1000.) as i16;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index as i32 * 1000;
    let y0 = n_index as i32 * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!

    // bottom-left grid intersection
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index), &(n_index)));
    // bottom-right
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    // top-left
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    // top-right
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = x - (x0 as f64);
    let dy = y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok(round_to_nearest_mm(se, sn, sg))

}

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

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_failed_ostn_hashmap_retrieval() {
        // we're try!ing this in the shift calculation function, so an Err is fine
        let eastings = 999;
        let northings = 999;
        let expected = (1., 1., 1.);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    fn test_hexkeys() {
        let val = 711;
        assert_eq!(HEXKEYS[&val], "2c7");
    }

}
<|endoftext|>