<commit_before>//! Simple FBX 7.4 binary loader.

use parser::binary::{Parser, ParserSource, FbxFooter, Event, Attributes};
use loader::binary::simple::{Result, Error, GenericNode};
pub use self::connections::{Connections, Connection};
pub use self::definitions::{Definitions, ObjectType};
pub use self::fbx_header_extension::{FbxHeaderExtension, CreationTimeStamp, SceneInfo};
pub use self::global_settings::GlobalSettings;
pub use self::properties70::{Properties70, PropertyMap, PropertyValue};

/// Tries to load the node attributes for parsing a child node.
///
/// The type of `$parser` should be `P: Parser<R> where R: ParserSource`, and
/// the type of `$load_attr` should be `F: FnOnce(&str, &mut Attributes) -> Result<T, _>`.
///
/// This will returns from the parent function on errors.
macro_rules! try_get_node_attrs {
    ($parser:expr, $load_attr:expr) => {
        match $parser.next_event()? {
            Event::StartNode(info) => $load_attr(info.name, info.attributes)?,
            Event::EndNode => break,
            ev => panic!("Unexpected node event: {:?}", ev),
        }
    }
}

/// Unwraps `$node_op` or returns `Error::MissingNode` error.
macro_rules! ensure_node_exists {
    ($node_opt:expr, $name:expr) => {
        $node_opt.ok_or_else(|| $crate::loader::binary::simple::Error::MissingNode($name.into()))?
    };
}

pub mod connections;
pub mod definitions;
pub mod fbx_header_extension;
pub mod global_settings;
pub mod properties70;

/// FBX 7.4 or later.
#[derive(Debug, Clone, PartialEq)]
pub struct Fbx7400 {
    /// FBX version.
    pub version: u32,
    /// `FBXHeaderExtension`.
    pub fbx_header_extension: FbxHeaderExtension,
    /// `FileId`.
    pub file_id: FileId,
    /// `CreationTime`.
    pub creation_time: CreationTime,
    /// `Creator`.
    pub creator: Creator,
    /// `References`.
    pub references: References,
    /// `GlobalSettings`.
    pub global_settings: GlobalSettings,
    /// `Documents`.
    pub documents: Documents,
    /// `Definitions`.
    pub definitions: Definitions,
    /// `Objects`.
    pub objects: Objects,
    /// `Connections`.
    pub connections: Connections,
    /// `Takes`.
    pub takes: Option<Takes>,
    /// FBX footer.
    pub footer: Option<FbxFooter>,
}

impl Fbx7400 {
    /// Loads FBX 7400 (or later) structure from the given parser.
    pub fn load_from_parser<R: ParserSource, P: Parser<R>>(
        version: u32,
        mut parser: P
    ) -> Result<Self> {
        info!("FBX version: {}, loading in FBX 7400 mode", version);

        let footer;
        let mut fbx_header_extension = None;
        let mut file_id = None;
        let mut creation_time = None;
        let mut creator = None;
        let mut global_settings = None;
        let mut documents = None;
        let mut references = None;
        let mut definitions = None;
        let mut objects = None;
        let mut connections = None;
        let mut takes = None;
        loop {
            let node_type = match parser.next_event()? {
                Event::StartFbx(_) |
                Event::EndNode => unreachable!(),
                Event::EndFbx(f) => {
                    footer = f.ok();
                    break;
                },
                Event::StartNode(info) => NodeType::load(info.name, info.attributes)?,
            };
            debug!("node_type: {:?}", node_type);
            match node_type {
                NodeType::FbxHeaderExtension => {
                    fbx_header_extension = Some(FbxHeaderExtension::load(parser.subtree_parser())?);
                },
                NodeType::FileId(attrs) => {
                    file_id = Some(FileId::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::CreationTime(attrs) => {
                    creation_time = Some(CreationTime::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::Creator(attrs) => {
                    creator = Some(Creator::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::GlobalSettings => {
                    global_settings = Some(GlobalSettings::load(parser.subtree_parser())?);
                },
                NodeType::Documents => {
                    documents = Some(Documents::load(parser.subtree_parser())?);
                },
                NodeType::References => {
                    references = Some(References::load(parser.subtree_parser())?);
                },
                NodeType::Definitions => {
                    definitions = Some(Definitions::load(parser.subtree_parser())?);
                },
                NodeType::Objects => {
                    objects = Some(Objects::load(parser.subtree_parser())?);
                },
                NodeType::Connections => {
                    connections = Some(Connections::load(parser.subtree_parser())?);
                },
                NodeType::Takes => {
                    takes = Some(Takes::load(parser.subtree_parser())?);
                },
            }
        }

        Ok(Fbx7400 {
            version: version,
            fbx_header_extension: ensure_node_exists!(fbx_header_extension, "FBXHeaderExtension"),
            file_id: ensure_node_exists!(file_id, "FileId"),
            creation_time: ensure_node_exists!(creation_time, "CreationTime"),
            creator: ensure_node_exists!(creator, "Creator"),
            global_settings: ensure_node_exists!(global_settings, "GlobalSettings"),
            documents: ensure_node_exists!(documents, "Documents"),
            references: ensure_node_exists!(references, "References"),
            definitions: ensure_node_exists!(definitions, "Definitions"),
            objects: ensure_node_exists!(objects, "Objects"),
            connections: ensure_node_exists!(connections, "Connections"),
            takes: takes,
            footer: footer,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum NodeType {
    FbxHeaderExtension,
    FileId(Vec<u8>),
    CreationTime(String),
    Creator(String),
    GlobalSettings,
    Documents,
    References,
    Definitions,
    Objects,
    Connections,
    Takes,
}

impl NodeType {
    /// Creates `NodeType` from the given node name.
    pub fn load<R: ParserSource>(name: &str, mut attrs: Attributes<R>) -> Result<Self> {
        use parser::binary::utils::AttributeValues;

        match name {
            "FBXHeaderExtension" => Ok(NodeType::FbxHeaderExtension),
            "FileId" => {
                <Vec<u8>>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::FileId)
            },
            "CreationTime" => {
                <String>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::CreationTime)
            },
            "Creator" => {
                <String>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::Creator)
            },
            "GlobalSettings" => Ok(NodeType::GlobalSettings),
            "Documents" => Ok(NodeType::Documents),
            "References" => Ok(NodeType::References),
            "Definitions" => Ok(NodeType::Definitions),
            "Objects" => Ok(NodeType::Objects),
            "Connections" => Ok(NodeType::Connections),
            "Takes" => Ok(NodeType::Takes),
            _ => Err(Error::UnexpectedNode(name.to_owned())),
        }
    }
}

/// `FileId`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub Vec<u8>);

impl FileId {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: Vec<u8>) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(FileId(attrs))
    }
}

/// `CreationTime`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreationTime(pub String);

impl CreationTime {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: String) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(CreationTime(attrs))
    }
}

/// `Creator`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Creator(pub String);

impl Creator {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: String) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(Creator(attrs))
    }
}

/// `Documents`.
#[derive(Debug, Clone, PartialEq)]
pub struct Documents {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Documents {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Documents { nodes: nodes })
    }
}

/// `References`.
#[derive(Debug, Clone, PartialEq)]
pub struct References {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl References {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(References { nodes: nodes })
    }
}

/// `Objects`.
#[derive(Debug, Clone, PartialEq)]
pub struct Objects {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Objects {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Objects { nodes: nodes })
    }
}

/// `Takes`.
#[derive(Debug, Clone, PartialEq)]
pub struct Takes {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Takes {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Takes { nodes: nodes })
    }
}
<commit_msg>Add a macro to easily define and impl child node attribute loader types<commit_after>//! Simple FBX 7.4 binary loader.

use parser::binary::{Parser, ParserSource, FbxFooter, Event, Attributes};
use loader::binary::simple::{Result, Error, GenericNode};
pub use self::connections::{Connections, Connection};
pub use self::definitions::{Definitions, ObjectType};
pub use self::fbx_header_extension::{FbxHeaderExtension, CreationTimeStamp, SceneInfo};
pub use self::global_settings::GlobalSettings;
pub use self::properties70::{Properties70, PropertyMap, PropertyValue};

/// Tries to load the node attributes for parsing a child node.
///
/// The type of `$parser` should be `P: Parser<R> where R: ParserSource`, and
/// the type of `$load_attr` should be `F: FnOnce(&str, &mut Attributes) -> Result<T, _>`.
///
/// This will returns from the parent function on errors.
macro_rules! try_get_node_attrs {
    ($parser:expr, $load_attr:expr) => {
        match $parser.next_event()? {
            Event::StartNode(info) => $load_attr(info.name, info.attributes)?,
            Event::EndNode => break,
            ev => panic!("Unexpected node event: {:?}", ev),
        }
    }
}

/// Unwraps `$node_op` or returns `Error::MissingNode` error.
macro_rules! ensure_node_exists {
    ($node_opt:expr, $name:expr) => {
        $node_opt.ok_or_else(|| $crate::loader::binary::simple::Error::MissingNode($name.into()))?
    };
}

macro_rules! child_attr_loader {
    (@load $enum_name:ident; $_name:ident; $_attrs:ident; $variant:ident($content:ty);
        => $load:block $(=> $_rest_load:block)*) => {
        $load
    };
    (@load $enum_name:ident; $name:ident; $attrs:ident; $variant:ident($content:ty);) => {
        <$content>::from_attributes(&mut $attrs)
            ?
            .ok_or_else(|| Error::InvalidAttribute($name.to_owned()))
            .map($enum_name::$variant)
    };
    (@load $enum_name:ident; $name:ident; $attrs:ident; $variant:ident;) => {
        Ok($enum_name::$variant)
    };
    ($enum_name:ident {
        $($node_name:expr => $variant:ident$(($content:ty))* $(=> $load:block)*),*,
    }) => {
        #[derive(Debug)]
        enum $enum_name {
            $($variant$(($content))*),*,
        }
        impl $enum_name {
            pub fn load<R: ParserSource>(name: &str, mut attrs: Attributes<R>)
                -> $crate::loader::binary::simple::Result<Self> {
                use parser::binary::utils::AttributeValues;

                match name {
                    $($node_name => child_attr_loader!{
                        @load $enum_name; name; attrs; $variant$(($content))*; $(=> $load)*
                    }),*,
                    _ => Err(Error::UnexpectedNode(name.to_owned())),
                }
            }
        }
    };
}

pub mod connections;
pub mod definitions;
pub mod fbx_header_extension;
pub mod global_settings;
pub mod properties70;

/// FBX 7.4 or later.
#[derive(Debug, Clone, PartialEq)]
pub struct Fbx7400 {
    /// FBX version.
    pub version: u32,
    /// `FBXHeaderExtension`.
    pub fbx_header_extension: FbxHeaderExtension,
    /// `FileId`.
    pub file_id: FileId,
    /// `CreationTime`.
    pub creation_time: CreationTime,
    /// `Creator`.
    pub creator: Creator,
    /// `References`.
    pub references: References,
    /// `GlobalSettings`.
    pub global_settings: GlobalSettings,
    /// `Documents`.
    pub documents: Documents,
    /// `Definitions`.
    pub definitions: Definitions,
    /// `Objects`.
    pub objects: Objects,
    /// `Connections`.
    pub connections: Connections,
    /// `Takes`.
    pub takes: Option<Takes>,
    /// FBX footer.
    pub footer: Option<FbxFooter>,
}

impl Fbx7400 {
    /// Loads FBX 7400 (or later) structure from the given parser.
    pub fn load_from_parser<R: ParserSource, P: Parser<R>>(
        version: u32,
        mut parser: P
    ) -> Result<Self> {
        info!("FBX version: {}, loading in FBX 7400 mode", version);

        let footer;
        let mut fbx_header_extension = None;
        let mut file_id = None;
        let mut creation_time = None;
        let mut creator = None;
        let mut global_settings = None;
        let mut documents = None;
        let mut references = None;
        let mut definitions = None;
        let mut objects = None;
        let mut connections = None;
        let mut takes = None;
        loop {
            let node_type = match parser.next_event()? {
                Event::StartFbx(_) |
                Event::EndNode => unreachable!(),
                Event::EndFbx(f) => {
                    footer = f.ok();
                    break;
                },
                Event::StartNode(info) => NodeType::load(info.name, info.attributes)?,
            };
            debug!("node_type: {:?}", node_type);
            match node_type {
                NodeType::FbxHeaderExtension => {
                    fbx_header_extension = Some(FbxHeaderExtension::load(parser.subtree_parser())?);
                },
                NodeType::FileId(attrs) => {
                    file_id = Some(FileId::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::CreationTime(attrs) => {
                    creation_time = Some(CreationTime::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::Creator(attrs) => {
                    creator = Some(Creator::load(parser.subtree_parser(), attrs)?);
                },
                NodeType::GlobalSettings => {
                    global_settings = Some(GlobalSettings::load(parser.subtree_parser())?);
                },
                NodeType::Documents => {
                    documents = Some(Documents::load(parser.subtree_parser())?);
                },
                NodeType::References => {
                    references = Some(References::load(parser.subtree_parser())?);
                },
                NodeType::Definitions => {
                    definitions = Some(Definitions::load(parser.subtree_parser())?);
                },
                NodeType::Objects => {
                    objects = Some(Objects::load(parser.subtree_parser())?);
                },
                NodeType::Connections => {
                    connections = Some(Connections::load(parser.subtree_parser())?);
                },
                NodeType::Takes => {
                    takes = Some(Takes::load(parser.subtree_parser())?);
                },
            }
        }

        Ok(Fbx7400 {
            version: version,
            fbx_header_extension: ensure_node_exists!(fbx_header_extension, "FBXHeaderExtension"),
            file_id: ensure_node_exists!(file_id, "FileId"),
            creation_time: ensure_node_exists!(creation_time, "CreationTime"),
            creator: ensure_node_exists!(creator, "Creator"),
            global_settings: ensure_node_exists!(global_settings, "GlobalSettings"),
            documents: ensure_node_exists!(documents, "Documents"),
            references: ensure_node_exists!(references, "References"),
            definitions: ensure_node_exists!(definitions, "Definitions"),
            objects: ensure_node_exists!(objects, "Objects"),
            connections: ensure_node_exists!(connections, "Connections"),
            takes: takes,
            footer: footer,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum NodeType {
    FbxHeaderExtension,
    FileId(Vec<u8>),
    CreationTime(String),
    Creator(String),
    GlobalSettings,
    Documents,
    References,
    Definitions,
    Objects,
    Connections,
    Takes,
}

impl NodeType {
    /// Creates `NodeType` from the given node name.
    pub fn load<R: ParserSource>(name: &str, mut attrs: Attributes<R>) -> Result<Self> {
        use parser::binary::utils::AttributeValues;

        match name {
            "FBXHeaderExtension" => Ok(NodeType::FbxHeaderExtension),
            "FileId" => {
                <Vec<u8>>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::FileId)
            },
            "CreationTime" => {
                <String>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::CreationTime)
            },
            "Creator" => {
                <String>::from_attributes(&mut attrs)
                    ?
                    .ok_or_else(|| Error::InvalidAttribute(name.to_owned()))
                    .map(NodeType::Creator)
            },
            "GlobalSettings" => Ok(NodeType::GlobalSettings),
            "Documents" => Ok(NodeType::Documents),
            "References" => Ok(NodeType::References),
            "Definitions" => Ok(NodeType::Definitions),
            "Objects" => Ok(NodeType::Objects),
            "Connections" => Ok(NodeType::Connections),
            "Takes" => Ok(NodeType::Takes),
            _ => Err(Error::UnexpectedNode(name.to_owned())),
        }
    }
}

/// `FileId`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub Vec<u8>);

impl FileId {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: Vec<u8>) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(FileId(attrs))
    }
}

/// `CreationTime`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreationTime(pub String);

impl CreationTime {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: String) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(CreationTime(attrs))
    }
}

/// `Creator`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Creator(pub String);

impl Creator {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P, attrs: String) -> Result<Self> {
        parser.skip_current_node()?;
        Ok(Creator(attrs))
    }
}

/// `Documents`.
#[derive(Debug, Clone, PartialEq)]
pub struct Documents {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Documents {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Documents { nodes: nodes })
    }
}

/// `References`.
#[derive(Debug, Clone, PartialEq)]
pub struct References {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl References {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(References { nodes: nodes })
    }
}

/// `Objects`.
#[derive(Debug, Clone, PartialEq)]
pub struct Objects {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Objects {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Objects { nodes: nodes })
    }
}

/// `Takes`.
#[derive(Debug, Clone, PartialEq)]
pub struct Takes {
    /// Child nodes.
    pub nodes: Vec<GenericNode>,
}

impl Takes {
    /// Loads node contents from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let nodes = GenericNode::load_from_parser(&mut parser)?.0;
        Ok(Takes { nodes: nodes })
    }
}
<|endoftext|>


<commit_before>extern crate glm;

pub fn wrap_rects(original: glm::IVec4, max: glm::UVec2) -> [Option<glm::IVec4>; 4] {
    let center = glm::uvec2(((original.x + original.z / 2 + max.x as i32) % max.x as i32) as u32,
                            ((original.y + original.w / 2 + max.y as i32) % max.y as i32) as u32);

    let dims = glm::uvec2(original.z as u32, original.w as u32);
    let mut ret = [None, None, None, None];
    let centers = get_wrapped_centers(center, dims, max);
    for (i, c) in centers.iter().enumerate() {
        ret[i] = match c {
            &Some(center) => {
                let left = center.x - original.z / 2;
                let top = center.y - original.w / 2;
                let rect = glm::ivec4(left, top, original.z, original.w);
                Some(rect)
            }
            &None => None,
        }
    }
    ret
}

fn get_wrapped_centers(original: glm::UVec2,
                           dims: glm::UVec2,
                           max_coords: glm::UVec2)
                           -> [Option<glm::IVec2>; 4] {
    let original = glm::ivec2(original.x as i32, original.y as i32);
    let half_dims = glm::ivec2(dims.x as i32 / 2, dims.y as i32 / 2);
    let left = original.x - half_dims.x;
    let right = original.x + half_dims.x;
    let bottom = original.y + half_dims.y;
    let top = original.y - half_dims.y;

    let side = if left < 0 {
        Some(glm::ivec2(left + max_coords.x as i32 + half_dims.x, original.y))
    } else if right > max_coords.x as i32 {
        Some(glm::ivec2(right % max_coords.x as i32 - half_dims.x, original.y))
    } else {
        None
    };

    let vert = if top < 0 {
        Some(glm::ivec2(original.x, top + max_coords.y as i32 + half_dims.y))
    } else if bottom > max_coords.y as i32 {
        Some(glm::ivec2(original.x, bottom % max_coords.y as i32 - half_dims.y))
    } else {
        None
    };

    let side_vert = match (side, vert) {
        (Some(side_center), Some(vert_center)) => Some(glm::ivec2(side_center.x, vert_center.y)),
        _ => None,
    };

    let centers = [Some(original), side, vert, side_vert];
    centers
}

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

    use super::*;

    #[test]
    fn no_wrapping() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(25, 15, 10, 7);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 1);
        assert_eq!(rect, rects[0]);
    }

    #[test]
    fn wrapping_left() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(-2, 16, 10, 8);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(38, 16, 10, 8), rects[1]);
    }

    #[test]
    fn wrapping_right() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(34, 16, 10, 13);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(-6, 16, 10, 13), rects[1]);
    }

    #[test]
    fn wrapping_bottom() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(27, 21, 6, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(27, -9, 6, 10), rects[1]);
    }

    #[test]
    fn wrapping_top() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(27, -3, 6, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(27, 27, 6, 10), rects[1]);
    }

    #[test]
    fn wrapping_corner() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(-2, -3, 10, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 4);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(38, -3, 10, 10), rects[1]);
        assert_eq!(glm::ivec4(-2, 27, 10, 10), rects[2]);
        assert_eq!(glm::ivec4(38, 27, 10, 10), rects[3]);
    }
}
<commit_msg>refactor window wrapping to not use the old center wrapper<commit_after>extern crate glm;

pub fn wrap_rects(original: glm::IVec4, max: glm::UVec2) -> [Option<glm::IVec4>; 4] {
    let max = glm::ivec2(max.x as i32, max.y as i32);
    let left = (original.x + max.x) % max.x;
    let right = left + original.z;
    let top = (original.y + max.y) % max.y;
    let bottom = top + original.w;
    let original = glm::ivec4(left, top, original.z, original.w);

    let side = if left < 0 {
        Some(glm::ivec4(left + max.x, top, original.z, original.w))
    } else if right > max.x as i32 {
        Some(glm::ivec4((right % max.x) - original.z, top, original.z, original.w))
    } else {
        None
    };

    let vert = if top < 0 {
        Some(glm::ivec4(left, top + max.y, original.z, original.w))
    } else if bottom > max.y {
        Some(glm::ivec4(left, bottom % max.y - original.w, original.z, original.w))
    } else {
        None
    };

    let side_vert = match (side, vert) {
        (Some(side_center), Some(vert_center)) => {
            Some(glm::ivec4(side_center.x, vert_center.y, original.z, original.w))
        }
        _ => None,
    };

    [Some(original), side, vert, side_vert]
}

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

    use super::*;

    #[test]
    fn no_wrapping() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(25, 15, 10, 7);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 1);
        assert_eq!(rect, rects[0]);
    }

    #[test]
    fn wrapping_left() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(-2, 16, 10, 8);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[1]);
        assert_eq!(glm::ivec4(38, 16, 10, 8), rects[0]);
    }

    #[test]
    fn wrapping_right() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(34, 16, 10, 13);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(-6, 16, 10, 13), rects[1]);
    }

    #[test]
    fn wrapping_bottom() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(27, 21, 6, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[0]);
        assert_eq!(glm::ivec4(27, -9, 6, 10), rects[1]);
    }

    #[test]
    fn wrapping_top() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(27, -3, 6, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 2);
        assert_eq!(rect, rects[1]);
        assert_eq!(glm::ivec4(27, 27, 6, 10), rects[0]);
    }

    #[test]
    fn wrapping_corner() {
        let max_coords = glm::uvec2(40, 30);
        let rect = glm::ivec4(-2, -3, 10, 10);
        let rects: Vec<_> = wrap_rects(rect, max_coords).iter().filter_map(|&x| x).collect();
        assert_eq!(rects.len(), 4);
        assert_eq!(rect, rects[3]);
        assert_eq!(glm::ivec4(38, -3, 10, 10), rects[2]);
        assert_eq!(glm::ivec4(-2, 27, 10, 10), rects[1]);
        assert_eq!(glm::ivec4(38, 27, 10, 10), rects[0]);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use {SdpLine, SdpBandwidth, SdpConnection};
use attribute_type::SdpAttribute;
use error::SdpParserError;

#[derive(Clone)]
pub struct SdpMediaLine {
    pub media: SdpMediaValue,
    pub port: u32,
    pub proto: SdpProtocolValue,
    pub formats: SdpFormatList,
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpMediaValue {
    Audio,
    Video,
    Application,
}

impl fmt::Display for SdpMediaValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpMediaValue::Audio => "Audio",
            SdpMediaValue::Video => "Video",
            SdpMediaValue::Application => "Application",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpProtocolValue {
    RtpSavpf,
    UdpTlsRtpSavpf,
    TcpTlsRtpSavpf,
    DtlsSctp,
    UdpDtlsSctp,
    TcpDtlsSctp,
}

impl fmt::Display for SdpProtocolValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
            SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
            SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
            SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
            SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
            SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone)]
pub enum SdpFormatList {
    Integers(Vec<u32>),
    Strings(Vec<String>),
}

impl fmt::Display for SdpFormatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
            SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
        }
    }
}

pub struct SdpMedia {
    media: SdpMediaLine,
    information: Option<String>,
    connection: Option<SdpConnection>,
    bandwidth: Vec<SdpBandwidth>,
    key: Option<String>,
    attribute: Vec<SdpAttribute>,
}

impl SdpMedia {
    pub fn new(media: SdpMediaLine) -> SdpMedia {
        SdpMedia {
            media,
            information: None,
            connection: None,
            bandwidth: Vec::new(),
            key: None,
            attribute: Vec::new(),
        }
    }

    pub fn get_type(&self) -> &SdpMediaValue {
        &self.media.media
    }

    pub fn get_port(&self) -> u32 {
        self.media.port
    }

    pub fn get_proto(&self) -> &SdpProtocolValue {
        &self.media.proto
    }

    pub fn get_formats(&self) -> &SdpFormatList {
        &self.media.formats
    }

    pub fn has_connection(&self) -> bool {
        self.connection.is_some()
    }

    pub fn has_bandwidth(&self) -> bool {
        !self.bandwidth.is_empty()
    }

    pub fn has_attributes(&self) -> bool {
        !self.attribute.is_empty()
    }

    pub fn add_attribute(&mut self, attr: SdpAttribute) {
        self.attribute.push(attr)
    }

    pub fn add_bandwidth(&mut self, bw: SdpBandwidth) {
        self.bandwidth.push(bw)
    }

    //TODO complain if connection is set already
    pub fn set_connection(&mut self, c: SdpConnection) {
        self.connection = Some(c);
    }

    //TODO complain if information is set already
    pub fn set_information(&mut self, i: String) {
        self.information = Some(i);
    }

    //TODO complain if key is set already
    pub fn set_key(&mut self, k: String) {
        self.key = Some(k);
    }
}
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserError> {
    Ok(match value.to_lowercase().as_ref() {
           "audio" => SdpMediaValue::Audio,
           "video" => SdpMediaValue::Video,
           "application" => SdpMediaValue::Application,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported media value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_media_token() {
    let audio = parse_media_token("audio");
    assert!(audio.is_ok());
    assert_eq!(audio.unwrap(), SdpMediaValue::Audio);
    let video = parse_media_token("VIDEO");
    assert!(video.is_ok());
    assert_eq!(video.unwrap(), SdpMediaValue::Video);
    let app = parse_media_token("aPplIcatIOn");
    assert!(app.is_ok());
    assert_eq!(app.unwrap(), SdpMediaValue::Application);

    assert!(parse_media_token("").is_err());
    assert!(parse_media_token("foobar").is_err());
}

fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserError> {
    Ok(match value.to_uppercase().as_ref() {
           "RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
           "UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
           "TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
           "DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
           "UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
           "TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported protocol value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_protocol_token() {
    let rtps = parse_protocol_token("rtp/savpf");
    assert!(rtps.is_ok());
    assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
    let udps = parse_protocol_token("udp/tls/rtp/savpf");
    assert!(udps.is_ok());
    assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
    let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
    assert!(tcps.is_ok());
    assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
    let dtls = parse_protocol_token("dtLs/ScTP");
    assert!(dtls.is_ok());
    assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
    let usctp = parse_protocol_token("udp/DTLS/sctp");
    assert!(usctp.is_ok());
    assert_eq!(usctp.unwrap(), SdpProtocolValue::UdpDtlsSctp);
    let tsctp = parse_protocol_token("tcp/dtls/SCTP");
    assert!(tsctp.is_ok());
    assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);

    assert!(parse_protocol_token("").is_err());
    assert!(parse_protocol_token("foobar").is_err());
}

pub fn parse_media(value: &str) -> Result<SdpLine, SdpParserError> {
    let mv: Vec<&str> = value.split_whitespace().collect();
    if mv.len() < 4 {
        return Err(SdpParserError::Line {
                       message: "media attribute must have at least four tokens".to_string(),
                       line: value.to_string(),
                   });
    }
    let media = parse_media_token(mv[0])?;
    let port = mv[1].parse::<u32>()?;
    if port > 65535 {
        return Err(SdpParserError::Line {
                       message: "media port token is too big".to_string(),
                       line: value.to_string(),
                   });
    }
    let proto = parse_protocol_token(mv[2])?;
    let fmt_slice: &[&str] = &mv[3..];
    let formats = match media {
        SdpMediaValue::Audio | SdpMediaValue::Video => {
            let mut fmt_vec: Vec<u32> = vec![];
            for num in fmt_slice {
                let fmt_num = num.parse::<u32>()?;
                match fmt_num {
                    0  |  // PCMU
                    8  |  // PCMA
                    9  |  // G722
                    13 |  // Comfort Noise
                    96 ... 127 => (),  // dynamic range
                    _ => return Err(SdpParserError::Line {
                          message: "format number in media line is out of range".to_string(),
                          line: value.to_string() }),
                };
                fmt_vec.push(fmt_num);
            }
            SdpFormatList::Integers(fmt_vec)
        }
        SdpMediaValue::Application => {
            let mut fmt_vec: Vec<String> = vec![];
            // TODO enforce length == 1 and content 'webrtc-datachannel' only?
            for token in fmt_slice {
                fmt_vec.push(String::from(*token));
            }
            SdpFormatList::Strings(fmt_vec)
        }
    };
    let m = SdpMediaLine {
        media,
        port,
        proto,
        formats,
    };
    println!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
    Ok(SdpLine::Media(m))
}

#[test]
fn test_media_works() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
    assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
    assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());

    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
    assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
}

#[test]
fn test_media_missing_token() {
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
}

#[test]
fn test_media_invalid_port_number() {
    assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_type() {
    assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_transport() {
    assert!(parse_media("audio 9 invalid/invalid 8").is_err());
}

#[test]
fn test_media_invalid_payload() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
}

pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
    let mut media_sections: Vec<SdpMedia> = Vec::new();
    let mut sdp_media = match lines[0] {
        SdpLine::Media(ref v) => SdpMedia::new(v.clone()),
        _ => {
            return Err(SdpParserError::Sequence {
                           message: "first line in media section needs to be a media line"
                               .to_string(),
                           line: None,
                       })
        }
    };
    for line in lines.iter().skip(1) {
        match *line {
            SdpLine::Information(ref v) => sdp_media.set_information(v.clone()),
            SdpLine::Connection(ref v) => sdp_media.set_connection(v.clone()),
            SdpLine::Bandwidth(ref v) => {
                sdp_media.add_bandwidth(v.clone());
            }
            SdpLine::Key(ref v) => sdp_media.set_key(v.clone()),
            SdpLine::Attribute(ref v) => {
                sdp_media.add_attribute(v.clone());
            }
            SdpLine::Media(ref v) => {
                media_sections.push(sdp_media);
                sdp_media = SdpMedia::new(v.clone());
            }

            SdpLine::Email(_) |
            SdpLine::Phone(_) |
            SdpLine::Origin(_) |
            SdpLine::Repeat(_) |
            SdpLine::Session(_) |
            SdpLine::Timing(_) |
            SdpLine::Uri(_) |
            SdpLine::Version(_) |
            SdpLine::Zone(_) => {
                return Err(SdpParserError::Sequence {
                               message: "invalid type in media section".to_string(),
                               line: None,
                           })
            }
        };
    }
    media_sections.push(sdp_media);
    Ok(media_sections)
}
// TODO add unit tests for parse_media_vector
<commit_msg>Add accessor for bandwidth. (#49)<commit_after>use std::fmt;
use {SdpLine, SdpBandwidth, SdpConnection};
use attribute_type::SdpAttribute;
use error::SdpParserError;

#[derive(Clone)]
pub struct SdpMediaLine {
    pub media: SdpMediaValue,
    pub port: u32,
    pub proto: SdpProtocolValue,
    pub formats: SdpFormatList,
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpMediaValue {
    Audio,
    Video,
    Application,
}

impl fmt::Display for SdpMediaValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpMediaValue::Audio => "Audio",
            SdpMediaValue::Video => "Video",
            SdpMediaValue::Application => "Application",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpProtocolValue {
    RtpSavpf,
    UdpTlsRtpSavpf,
    TcpTlsRtpSavpf,
    DtlsSctp,
    UdpDtlsSctp,
    TcpDtlsSctp,
}

impl fmt::Display for SdpProtocolValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
            SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
            SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
            SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
            SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
            SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone)]
pub enum SdpFormatList {
    Integers(Vec<u32>),
    Strings(Vec<String>),
}

impl fmt::Display for SdpFormatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
            SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
        }
    }
}

pub struct SdpMedia {
    media: SdpMediaLine,
    information: Option<String>,
    connection: Option<SdpConnection>,
    bandwidth: Vec<SdpBandwidth>,
    key: Option<String>,
    attribute: Vec<SdpAttribute>,
}

impl SdpMedia {
    pub fn new(media: SdpMediaLine) -> SdpMedia {
        SdpMedia {
            media,
            information: None,
            connection: None,
            bandwidth: Vec::new(),
            key: None,
            attribute: Vec::new(),
        }
    }

    pub fn get_type(&self) -> &SdpMediaValue {
        &self.media.media
    }

    pub fn get_port(&self) -> u32 {
        self.media.port
    }

    pub fn get_proto(&self) -> &SdpProtocolValue {
        &self.media.proto
    }

    pub fn get_formats(&self) -> &SdpFormatList {
        &self.media.formats
    }

    pub fn has_connection(&self) -> bool {
        self.connection.is_some()
    }

    pub fn has_bandwidth(&self) -> bool {
        !self.bandwidth.is_empty()
    }

    pub fn get_bandwidth(&self) -> &Vec<SdpBandwidth> {
        &self.bandwidth
    }

    pub fn has_attributes(&self) -> bool {
        !self.attribute.is_empty()
    }

    pub fn add_attribute(&mut self, attr: SdpAttribute) {
        self.attribute.push(attr)
    }

    pub fn add_bandwidth(&mut self, bw: SdpBandwidth) {
        self.bandwidth.push(bw)
    }

    //TODO complain if connection is set already
    pub fn set_connection(&mut self, c: SdpConnection) {
        self.connection = Some(c);
    }

    //TODO complain if information is set already
    pub fn set_information(&mut self, i: String) {
        self.information = Some(i);
    }

    //TODO complain if key is set already
    pub fn set_key(&mut self, k: String) {
        self.key = Some(k);
    }
}
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserError> {
    Ok(match value.to_lowercase().as_ref() {
           "audio" => SdpMediaValue::Audio,
           "video" => SdpMediaValue::Video,
           "application" => SdpMediaValue::Application,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported media value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_media_token() {
    let audio = parse_media_token("audio");
    assert!(audio.is_ok());
    assert_eq!(audio.unwrap(), SdpMediaValue::Audio);
    let video = parse_media_token("VIDEO");
    assert!(video.is_ok());
    assert_eq!(video.unwrap(), SdpMediaValue::Video);
    let app = parse_media_token("aPplIcatIOn");
    assert!(app.is_ok());
    assert_eq!(app.unwrap(), SdpMediaValue::Application);

    assert!(parse_media_token("").is_err());
    assert!(parse_media_token("foobar").is_err());
}

fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserError> {
    Ok(match value.to_uppercase().as_ref() {
           "RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
           "UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
           "TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
           "DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
           "UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
           "TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported protocol value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_protocol_token() {
    let rtps = parse_protocol_token("rtp/savpf");
    assert!(rtps.is_ok());
    assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
    let udps = parse_protocol_token("udp/tls/rtp/savpf");
    assert!(udps.is_ok());
    assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
    let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
    assert!(tcps.is_ok());
    assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
    let dtls = parse_protocol_token("dtLs/ScTP");
    assert!(dtls.is_ok());
    assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
    let usctp = parse_protocol_token("udp/DTLS/sctp");
    assert!(usctp.is_ok());
    assert_eq!(usctp.unwrap(), SdpProtocolValue::UdpDtlsSctp);
    let tsctp = parse_protocol_token("tcp/dtls/SCTP");
    assert!(tsctp.is_ok());
    assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);

    assert!(parse_protocol_token("").is_err());
    assert!(parse_protocol_token("foobar").is_err());
}

pub fn parse_media(value: &str) -> Result<SdpLine, SdpParserError> {
    let mv: Vec<&str> = value.split_whitespace().collect();
    if mv.len() < 4 {
        return Err(SdpParserError::Line {
                       message: "media attribute must have at least four tokens".to_string(),
                       line: value.to_string(),
                   });
    }
    let media = parse_media_token(mv[0])?;
    let port = mv[1].parse::<u32>()?;
    if port > 65535 {
        return Err(SdpParserError::Line {
                       message: "media port token is too big".to_string(),
                       line: value.to_string(),
                   });
    }
    let proto = parse_protocol_token(mv[2])?;
    let fmt_slice: &[&str] = &mv[3..];
    let formats = match media {
        SdpMediaValue::Audio | SdpMediaValue::Video => {
            let mut fmt_vec: Vec<u32> = vec![];
            for num in fmt_slice {
                let fmt_num = num.parse::<u32>()?;
                match fmt_num {
                    0  |  // PCMU
                    8  |  // PCMA
                    9  |  // G722
                    13 |  // Comfort Noise
                    96 ... 127 => (),  // dynamic range
                    _ => return Err(SdpParserError::Line {
                          message: "format number in media line is out of range".to_string(),
                          line: value.to_string() }),
                };
                fmt_vec.push(fmt_num);
            }
            SdpFormatList::Integers(fmt_vec)
        }
        SdpMediaValue::Application => {
            let mut fmt_vec: Vec<String> = vec![];
            // TODO enforce length == 1 and content 'webrtc-datachannel' only?
            for token in fmt_slice {
                fmt_vec.push(String::from(*token));
            }
            SdpFormatList::Strings(fmt_vec)
        }
    };
    let m = SdpMediaLine {
        media,
        port,
        proto,
        formats,
    };
    println!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
    Ok(SdpLine::Media(m))
}

#[test]
fn test_media_works() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
    assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
    assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());

    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
    assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
}

#[test]
fn test_media_missing_token() {
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
}

#[test]
fn test_media_invalid_port_number() {
    assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_type() {
    assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_transport() {
    assert!(parse_media("audio 9 invalid/invalid 8").is_err());
}

#[test]
fn test_media_invalid_payload() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
}

pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
    let mut media_sections: Vec<SdpMedia> = Vec::new();
    let mut sdp_media = match lines[0] {
        SdpLine::Media(ref v) => SdpMedia::new(v.clone()),
        _ => {
            return Err(SdpParserError::Sequence {
                           message: "first line in media section needs to be a media line"
                               .to_string(),
                           line: None,
                       })
        }
    };
    for line in lines.iter().skip(1) {
        match *line {
            SdpLine::Information(ref v) => sdp_media.set_information(v.clone()),
            SdpLine::Connection(ref v) => sdp_media.set_connection(v.clone()),
            SdpLine::Bandwidth(ref v) => {
                sdp_media.add_bandwidth(v.clone());
            }
            SdpLine::Key(ref v) => sdp_media.set_key(v.clone()),
            SdpLine::Attribute(ref v) => {
                sdp_media.add_attribute(v.clone());
            }
            SdpLine::Media(ref v) => {
                media_sections.push(sdp_media);
                sdp_media = SdpMedia::new(v.clone());
            }

            SdpLine::Email(_) |
            SdpLine::Phone(_) |
            SdpLine::Origin(_) |
            SdpLine::Repeat(_) |
            SdpLine::Session(_) |
            SdpLine::Timing(_) |
            SdpLine::Uri(_) |
            SdpLine::Version(_) |
            SdpLine::Zone(_) => {
                return Err(SdpParserError::Sequence {
                               message: "invalid type in media section".to_string(),
                               line: None,
                           })
            }
        };
    }
    media_sections.push(sdp_media);
    Ok(media_sections)
}
// TODO add unit tests for parse_media_vector
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! texture data.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. This is mostly due to OpenGL
/// and Metal being braindamaged and not allowing, for example, a texture
/// previously used as Texture2D to be used as Texture3D. The available
/// texture types are restricted by what Metal exposes.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    Texture1D,
    Texture1DArray,
    Texture2D,
    Texture2DArray,
    TextureCube,
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// Portability note: textures larger than 1024px in any dimension are
/// unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<commit_msg>Clarify the role of TextureKind<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! texture data.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. The available texture types are restricted by what
/// Metal exposes, though this could conceivably be extended in the future. Note that a single
/// texture can *only* ever be of one kind. A texture created as `Texture2D` will forever be
/// `Texture2D`.
// TODO: "Texture views" let you get around that limitation.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    Texture1D,
    Texture1DArray,
    Texture2D,
    Texture2DArray,
    TextureCube,
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// Portability note: textures larger than 1024px in any dimension are
/// unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::mem;

use basic::Type;
use rand::{Rng, Rand};
use util::memory::{ByteBuffer, ByteBufferPtr};

// ----------------------------------------------------------------------
// Types connect Parquet physical types with Rust-specific types

// TODO: alignment?
// TODO: we could also use [u32; 3], however it seems there is no easy way
//   to convert [u32] to [u32; 3] in decoding.
#[derive(Clone, Debug)]
pub struct Int96 {
  value: Option<Vec<u32>>,
}

impl Int96 {
  pub fn new() -> Self {
    Int96 { value: None }
  }

  pub fn data(&self) -> &[u32] {
    assert!(self.value.is_some());
    &self.value.as_ref().unwrap()
  }

  pub fn set_data(&mut self, v: Vec<u32>) {
    assert_eq!(v.len(), 3);
    self.value = Some(v);
  }
}

impl Default for Int96 {
  fn default() -> Self { Int96 { value: None } }
}

impl PartialEq for Int96 {
  fn eq(&self, other: &Int96) -> bool {
    self.data() == other.data()
  }
}

impl From<Vec<u32>> for Int96 {
  fn from(buf: Vec<u32>) -> Int96 {
    assert_eq!(buf.len(), 3);
    Self { value: Some(buf) }
  }
}

impl Rand for Int96 {
  fn rand<R: Rng>(rng: &mut R) -> Self {
    let mut result = Int96::new();
    let mut value = vec!();
    for _ in 0..3 {
      value.push(rng.gen::<u32>());
    }
    result.set_data(value);
    result
  }
}

#[derive(Clone, Debug)]
pub struct ByteArray {
  data: Option<ByteBufferPtr>,
}

impl ByteArray {
  pub fn new() -> Self {
    ByteArray { data: None }
  }

  pub fn len(&self) -> usize {
    assert!(self.data.is_some());
    self.data.as_ref().unwrap().len()
  }

  pub fn data(&self) -> &[u8] {
    assert!(self.data.is_some());
    self.data.as_ref().unwrap().as_ref()
  }

  pub fn set_data(&mut self, data: ByteBufferPtr) {
    self.data = Some(data);
  }
}

impl From<Vec<u8>> for ByteArray {
  fn from(buf: Vec<u8>) -> ByteArray {
    Self { data: Some(ByteBufferPtr::new(buf)) }
  }
}

impl From<ByteBufferPtr> for ByteArray {
  fn from(ptr: ByteBufferPtr) -> ByteArray {
    Self { data: Some(ptr) }
  }
}

impl From<ByteBuffer> for ByteArray {
  fn from(mut buf: ByteBuffer) -> ByteArray {
    Self { data: Some(buf.consume()) }
  }
}

impl Default for ByteArray {
  fn default() -> Self { ByteArray { data: None } }
}

impl PartialEq for ByteArray {
  fn eq(&self, other: &ByteArray) -> bool {
    self.data() == other.data()
  }
}

impl Rand for ByteArray {
  fn rand<R: Rng>(rng: &mut R) -> Self {
    let mut result = ByteArray::new();
    let mut value = vec!();
    let len = rng.gen_range::<usize>(0, 128);
    for _ in 0..len {
      value.push(rng.gen_range(0, 255) & 0xFF);
    }
    result.set_data(ByteBufferPtr::new(value));
    result
  }
}

// ----------------------------------------------------------------------
// AsBytes converts an instance of data type to a slice of u8

pub trait AsBytes {
  fn as_bytes(&self) -> &[u8];
}

impl AsBytes for bool {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const bool as *const u8, 1)
    }
  }
}

impl AsBytes for i32 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const i32 as *const u8, 4)
    }
  }
}

impl AsBytes for i64 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const i64 as *const u8, 8)
    }
  }
}

impl AsBytes for Int96 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self.data() as *const [u32] as *const u8, 12)
    }
  }
}

impl AsBytes for f32 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const f32 as *const u8, 4)
    }
  }
}

impl AsBytes for f64 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const f64 as *const u8, 8)
    }
  }
}

impl AsBytes for ByteArray {
  fn as_bytes(&self) -> &[u8] {
    self.data()
  }
}

impl AsBytes for Vec<u8> {
  fn as_bytes(&self) -> &[u8] {
    self.as_slice()
  }
}

impl<'a> AsBytes for &'a str {
  fn as_bytes(&self) -> &[u8] {
    (self as &str).as_bytes()
  }
}

impl AsBytes for str {
  fn as_bytes(&self) -> &[u8] {
    (self as &str).as_bytes()
  }
}

// ----------------------------------------------------------------------
// DataType trait, which contains the Parquet physical type info as well as
// the Rust primitive type presentation.

pub trait DataType {
  type T: ::std::cmp::PartialEq + ::std::fmt::Debug + ::std::default::Default
    + ::std::clone::Clone + Rand + AsBytes;
  fn get_physical_type() -> Type;
  fn get_type_size() -> usize;
}

macro_rules! make_type {
  ($name:ident, $physical_ty:path, $native_ty:ty, $size:expr) => {
    pub struct $name {
    }

    impl DataType for $name {
      type T = $native_ty;

      fn get_physical_type() -> Type {
        $physical_ty
      }

      fn get_type_size() -> usize {
        $size
      }
    }
  };
}

/// Generate struct definitions for all physical types

make_type!(BoolType, Type::BOOLEAN, bool, 1);
make_type!(Int32Type, Type::INT32, i32, 4);
make_type!(Int64Type, Type::INT64, i64, 8);
make_type!(Int96Type, Type::INT96, Int96, mem::size_of::<Int96>());
make_type!(FloatType, Type::FLOAT, f32, 4);
make_type!(DoubleType, Type::DOUBLE, f64, 8);
make_type!(ByteArrayType, Type::BYTE_ARRAY, ByteArray, mem::size_of::<ByteArray>());
make_type!(FixedLenByteArrayType, Type::FIXED_LEN_BYTE_ARRAY,
           ByteArray, mem::size_of::<ByteArray>());

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

  #[test]
  fn test_as_bytes() {
    assert_eq!(false.as_bytes(), &[0]);
    assert_eq!(true.as_bytes(), &[1]);
    assert_eq!((7 as i32).as_bytes(), &[7, 0, 0, 0]);
    assert_eq!((555 as i32).as_bytes(), &[43, 2, 0, 0]);
    assert_eq!(i32::max_value().as_bytes(), &[255, 255, 255, 127]);
    assert_eq!(i32::min_value().as_bytes(), &[0, 0, 0, 128]);
    assert_eq!((7 as i64).as_bytes(), &[7, 0, 0, 0, 0, 0, 0, 0]);
    assert_eq!((555 as i64).as_bytes(), &[43, 2, 0, 0, 0, 0, 0, 0]);
    assert_eq!((i64::max_value()).as_bytes(), &[255, 255, 255, 255, 255, 255, 255, 127]);
    assert_eq!((i64::min_value()).as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 128]);
    assert_eq!((3.14 as f32).as_bytes(), &[195, 245, 72, 64]);
    assert_eq!((3.14 as f64).as_bytes(), &[31, 133, 235, 81, 184, 30, 9, 64]);
    assert_eq!("hello".as_bytes(), &[b'h', b'e', b'l', b'l', b'o']);
    assert_eq!(Vec::from("hello".as_bytes()).as_bytes(), &[b'h', b'e', b'l', b'l', b'o']);

    // Test Int96
    let i96 = Int96::from(vec![1, 2, 3]);
    assert_eq!(i96.as_bytes(), &[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]);

    // Test ByteArray
    let ba = ByteArray::from(vec![1, 2, 3]);
    assert_eq!(ba.as_bytes(), &[1, 2, 3]);
  }
}
<commit_msg>Add AsBytes for u8<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::mem;

use basic::Type;
use rand::{Rng, Rand};
use util::memory::{ByteBuffer, ByteBufferPtr};

// ----------------------------------------------------------------------
// Types connect Parquet physical types with Rust-specific types

// TODO: alignment?
// TODO: we could also use [u32; 3], however it seems there is no easy way
//   to convert [u32] to [u32; 3] in decoding.
#[derive(Clone, Debug)]
pub struct Int96 {
  value: Option<Vec<u32>>,
}

impl Int96 {
  pub fn new() -> Self {
    Int96 { value: None }
  }

  pub fn data(&self) -> &[u32] {
    assert!(self.value.is_some());
    &self.value.as_ref().unwrap()
  }

  pub fn set_data(&mut self, v: Vec<u32>) {
    assert_eq!(v.len(), 3);
    self.value = Some(v);
  }
}

impl Default for Int96 {
  fn default() -> Self { Int96 { value: None } }
}

impl PartialEq for Int96 {
  fn eq(&self, other: &Int96) -> bool {
    self.data() == other.data()
  }
}

impl From<Vec<u32>> for Int96 {
  fn from(buf: Vec<u32>) -> Int96 {
    assert_eq!(buf.len(), 3);
    Self { value: Some(buf) }
  }
}

impl Rand for Int96 {
  fn rand<R: Rng>(rng: &mut R) -> Self {
    let mut result = Int96::new();
    let mut value = vec!();
    for _ in 0..3 {
      value.push(rng.gen::<u32>());
    }
    result.set_data(value);
    result
  }
}

#[derive(Clone, Debug)]
pub struct ByteArray {
  data: Option<ByteBufferPtr>,
}

impl ByteArray {
  pub fn new() -> Self {
    ByteArray { data: None }
  }

  pub fn len(&self) -> usize {
    assert!(self.data.is_some());
    self.data.as_ref().unwrap().len()
  }

  pub fn data(&self) -> &[u8] {
    assert!(self.data.is_some());
    self.data.as_ref().unwrap().as_ref()
  }

  pub fn set_data(&mut self, data: ByteBufferPtr) {
    self.data = Some(data);
  }
}

impl From<Vec<u8>> for ByteArray {
  fn from(buf: Vec<u8>) -> ByteArray {
    Self { data: Some(ByteBufferPtr::new(buf)) }
  }
}

impl From<ByteBufferPtr> for ByteArray {
  fn from(ptr: ByteBufferPtr) -> ByteArray {
    Self { data: Some(ptr) }
  }
}

impl From<ByteBuffer> for ByteArray {
  fn from(mut buf: ByteBuffer) -> ByteArray {
    Self { data: Some(buf.consume()) }
  }
}

impl Default for ByteArray {
  fn default() -> Self { ByteArray { data: None } }
}

impl PartialEq for ByteArray {
  fn eq(&self, other: &ByteArray) -> bool {
    self.data() == other.data()
  }
}

impl Rand for ByteArray {
  fn rand<R: Rng>(rng: &mut R) -> Self {
    let mut result = ByteArray::new();
    let mut value = vec!();
    let len = rng.gen_range::<usize>(0, 128);
    for _ in 0..len {
      value.push(rng.gen_range(0, 255) & 0xFF);
    }
    result.set_data(ByteBufferPtr::new(value));
    result
  }
}

// ----------------------------------------------------------------------
// AsBytes converts an instance of data type to a slice of u8

pub trait AsBytes {
  fn as_bytes(&self) -> &[u8];
}

impl AsBytes for bool {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const bool as *const u8, 1)
    }
  }
}

impl AsBytes for u8 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const u8, 1)
    }
  }
}

impl AsBytes for i32 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const i32 as *const u8, 4)
    }
  }
}

impl AsBytes for i64 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const i64 as *const u8, 8)
    }
  }
}

impl AsBytes for Int96 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self.data() as *const [u32] as *const u8, 12)
    }
  }
}

impl AsBytes for f32 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const f32 as *const u8, 4)
    }
  }
}

impl AsBytes for f64 {
  fn as_bytes(&self) -> &[u8] {
    unsafe {
      ::std::slice::from_raw_parts(self as *const f64 as *const u8, 8)
    }
  }
}

impl AsBytes for ByteArray {
  fn as_bytes(&self) -> &[u8] {
    self.data()
  }
}

impl AsBytes for Vec<u8> {
  fn as_bytes(&self) -> &[u8] {
    self.as_slice()
  }
}

impl<'a> AsBytes for &'a str {
  fn as_bytes(&self) -> &[u8] {
    (self as &str).as_bytes()
  }
}

impl AsBytes for str {
  fn as_bytes(&self) -> &[u8] {
    (self as &str).as_bytes()
  }
}

// ----------------------------------------------------------------------
// DataType trait, which contains the Parquet physical type info as well as
// the Rust primitive type presentation.

pub trait DataType {
  type T: ::std::cmp::PartialEq + ::std::fmt::Debug + ::std::default::Default
    + ::std::clone::Clone + Rand + AsBytes;
  fn get_physical_type() -> Type;
  fn get_type_size() -> usize;
}

macro_rules! make_type {
  ($name:ident, $physical_ty:path, $native_ty:ty, $size:expr) => {
    pub struct $name {
    }

    impl DataType for $name {
      type T = $native_ty;

      fn get_physical_type() -> Type {
        $physical_ty
      }

      fn get_type_size() -> usize {
        $size
      }
    }
  };
}

/// Generate struct definitions for all physical types

make_type!(BoolType, Type::BOOLEAN, bool, 1);
make_type!(Int32Type, Type::INT32, i32, 4);
make_type!(Int64Type, Type::INT64, i64, 8);
make_type!(Int96Type, Type::INT96, Int96, mem::size_of::<Int96>());
make_type!(FloatType, Type::FLOAT, f32, 4);
make_type!(DoubleType, Type::DOUBLE, f64, 8);
make_type!(ByteArrayType, Type::BYTE_ARRAY, ByteArray, mem::size_of::<ByteArray>());
make_type!(FixedLenByteArrayType, Type::FIXED_LEN_BYTE_ARRAY,
           ByteArray, mem::size_of::<ByteArray>());

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

  #[test]
  fn test_as_bytes() {
    assert_eq!(false.as_bytes(), &[0]);
    assert_eq!(true.as_bytes(), &[1]);
    assert_eq!((7 as i32).as_bytes(), &[7, 0, 0, 0]);
    assert_eq!((555 as i32).as_bytes(), &[43, 2, 0, 0]);
    assert_eq!(i32::max_value().as_bytes(), &[255, 255, 255, 127]);
    assert_eq!(i32::min_value().as_bytes(), &[0, 0, 0, 128]);
    assert_eq!((7 as i64).as_bytes(), &[7, 0, 0, 0, 0, 0, 0, 0]);
    assert_eq!((555 as i64).as_bytes(), &[43, 2, 0, 0, 0, 0, 0, 0]);
    assert_eq!((i64::max_value()).as_bytes(), &[255, 255, 255, 255, 255, 255, 255, 127]);
    assert_eq!((i64::min_value()).as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 128]);
    assert_eq!((3.14 as f32).as_bytes(), &[195, 245, 72, 64]);
    assert_eq!((3.14 as f64).as_bytes(), &[31, 133, 235, 81, 184, 30, 9, 64]);
    assert_eq!("hello".as_bytes(), &[b'h', b'e', b'l', b'l', b'o']);
    assert_eq!(Vec::from("hello".as_bytes()).as_bytes(), &[b'h', b'e', b'l', b'l', b'o']);

    // Test Int96
    let i96 = Int96::from(vec![1, 2, 3]);
    assert_eq!(i96.as_bytes(), &[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]);

    // Test ByteArray
    let ba = ByteArray::from(vec![1, 2, 3]);
    assert_eq!(ba.as_bytes(), &[1, 2, 3]);
  }
}
<|endoftext|>


<commit_before>//! module for finite automation.

use std::collections::HashSet;
use std::hash::Hash;

/// The rule that moves state from one to another.
///
/// `S` - the type parameter of state.
///
/// `T` - the type parameter of input symbol.
#[deriving(PartialEq, Eq, Hash)]
pub struct Rule<S, T> {
  pub state: S,
  pub symbol: Option<T>,
  pub next_state: S
}

impl<S: PartialEq, T: PartialEq> Rule<S, T> {
  /// determine whether the rule applies to the given state and symbol
  pub fn apply_to(&self, state: &S, symbol: &Option<T>) -> bool {
    self.state == *state && self.symbol == *symbol
  }
}

/// The transition relation in DFA,
/// containing all the rules needed by the DFA.
pub struct DFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash, T: Eq + Hash> DFATransitions<S, T> {
  /// get the next state for the given state and symbol
  pub fn next_state(&self, state: &S, symbol: &Option<T>) -> Option<&S> {
    self.rule_for(state, symbol).map(|rule| &rule.next_state)
  }

  fn rule_for(&self, state: &S, symbol: &Option<T>) -> Option<&Rule<S, T>> {
    self.rules.iter().find(|rule| { rule.apply_to(state, symbol) })
  }
}

/// A running dfa instance, constructed from a DFA model
pub struct DFA<'a, S: 'a, T: 'a> {
  state: S, // current state
  accept_states: &'a HashSet<S>, // set of accept states
  transitions: &'a DFATransitions<S, T>
}

impl<'a, S: Eq + Hash + Clone, T: Eq + Hash> DFA<'a, S, T> {
  pub fn accepted(&self) -> bool {
    self.accept_states.contains(&self.state)
  }

  pub fn read_symbol(&mut self, sym: &Option<T>) {
    self.state = self.transitions.next_state(&self.state, sym)
                                 .expect("unknown input symbol")
                                 .clone()
  }
}

/// DFA template that can generates dfa instance
pub struct DFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: DFATransitions<S, T>
}

impl<S: Clone + Eq + Hash, T: Eq + Hash> DFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_dfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a dfa instance
  fn gen_dfa(&self) -> DFA<S, T> {
    DFA {
      state: self.start_state.clone(),
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}

/// The transition relation in NFA,
/// containing all the rules needed by the NFA.
pub struct NFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFATransitions<S, T> {
  fn empty_move(&self, states: HashSet<S>) -> HashSet<S> {
    let mut nexts = self.next_states(&states, &None);
    if nexts.is_subset(&states) {
      states
    } else {
      nexts.extend(states.into_iter());
      self.empty_move(nexts)
    }
  }

  pub fn next_states(&self, states: &HashSet<S>, symbol: &Option<T>) -> HashSet<S> {
    states.iter().flat_map(|state| {
      // NOTE: use `move_iter` instead of `iter`
      self.next_states_for(state, symbol).into_iter()
    }).collect()
  }

  /// get the next state for the given state and symbol
  fn next_states_for(&self, state: &S, symbol: &Option<T>) -> HashSet<S> {
    self.rules.iter().filter_map(|rule| {
      if rule.apply_to(state, symbol) { Some(rule.next_state.clone()) } else { None }
    }).collect()
  }

  fn rules_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> HashSet<&'a Rule<S, T>> {
    self.rules.iter()
              .filter(|rule| { rule.apply_to(state, symbol) })
              .collect()
  }
}

struct NFA<'a, S: 'a, T: 'a> {
  states: HashSet<S>,
  accept_states: &'a HashSet<S>,
  transitions: &'a NFATransitions<S, T>
}

impl<'a, S: Eq + Hash + Clone, T: Eq + Hash> NFA<'a, S, T> {
  pub fn read_symbol(&mut self, symbol: &Option<T>) {
    // do empty moves
    self.states = self.transitions.empty_move(self.states.clone());

    self.states = self.transitions.next_states(&self.states, symbol)
                                  .iter()
                                  .map(|state| { state.clone() }).collect();

    self.states = self.transitions.empty_move(self.states.clone());
  }

  pub fn accepted(&self) -> bool {
    !self.states.is_disjoint(self.accept_states)
  }
}

pub struct NFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: NFATransitions<S, T>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_nfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a nfa instance
  fn gen_nfa(&self) -> NFA<S, T> {
    let mut start_states = HashSet::new();
    start_states.insert(self.start_state.clone());
    NFA {
      states: start_states,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}
<commit_msg>improve the code, remove unnecessary restrict<commit_after>//! module for finite automation.

use std::collections::HashSet;
use std::hash::Hash;

/// The rule that moves state from one to another.
///
/// `S` - the type parameter of state.
///
/// `T` - the type parameter of input symbol.
#[deriving(PartialEq, Eq, Hash)]
pub struct Rule<S, T> {
  pub state: S,
  pub symbol: Option<T>,
  pub next_state: S
}

impl<S: PartialEq, T: PartialEq> Rule<S, T> {
  /// determine whether the rule applies to the given state and symbol
  pub fn apply_to(&self, state: &S, symbol: &Option<T>) -> bool {
    self.state == *state && self.symbol == *symbol
  }
}

/// The transition relation in DFA,
/// containing all the rules needed by the DFA.
pub struct DFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash, T: Eq + Hash> DFATransitions<S, T> {
  /// get the next state for the given state and symbol
  pub fn next_state<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a S> {
    self.rule_for(state, symbol).map(|rule| &rule.next_state)
  }

  fn rule_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a Rule<S, T>> {
    self.rules.iter().find(|rule| { rule.apply_to(state, symbol) })
  }
}

/// A running dfa instance, constructed from a DFA model
pub struct DFA<'a, S: 'a, T: 'a> {
  state: &'a S, // current state
  accept_states: &'a HashSet<S>, // set of accept states
  transitions: &'a DFATransitions<S, T>
}

impl<'a, S: Eq + Hash, T: Eq + Hash> DFA<'a, S, T> {
  pub fn accepted(&self) -> bool {
    self.accept_states.contains(self.state)
  }

  pub fn read_symbol(&mut self, sym: &Option<T>) {
    self.state = self.transitions.next_state(self.state, sym)
                                 .expect("unknown input symbol")
  }
}

/// DFA template that can generates dfa instance
pub struct DFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: DFATransitions<S, T>
}

impl<S: Eq + Hash, T: Eq + Hash> DFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_dfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a dfa instance
  fn gen_dfa(&self) -> DFA<S, T> {
    DFA {
      state: &self.start_state,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}

/// The transition relation in NFA,
/// containing all the rules needed by the NFA.
pub struct NFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFATransitions<S, T> {
  fn empty_move(&self, states: HashSet<S>) -> HashSet<S> {
    let mut nexts = self.next_states(&states, &None);
    if nexts.is_subset(&states) {
      states
    } else {
      nexts.extend(states.into_iter());
      self.empty_move(nexts)
    }
  }

  pub fn next_states(&self, states: &HashSet<S>, symbol: &Option<T>) -> HashSet<S> {
    states.iter().flat_map(|state| {
      // NOTE: use `move_iter` instead of `iter`
      self.next_states_for(state, symbol).into_iter()
    }).collect()
  }

  /// get the next state for the given state and symbol
  fn next_states_for(&self, state: &S, symbol: &Option<T>) -> HashSet<S> {
    self.rules.iter().filter_map(|rule| {
      if rule.apply_to(state, symbol) { Some(rule.next_state.clone()) } else { None }
    }).collect()
  }

  fn rules_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> HashSet<&'a Rule<S, T>> {
    self.rules.iter()
              .filter(|rule| { rule.apply_to(state, symbol) })
              .collect()
  }
}

struct NFA<'a, S: 'a, T: 'a> {
  states: HashSet<S>,
  accept_states: &'a HashSet<S>,
  transitions: &'a NFATransitions<S, T>
}

impl<'a, S: Eq + Hash + Clone, T: Eq + Hash> NFA<'a, S, T> {
  pub fn read_symbol(&mut self, symbol: &Option<T>) {
    // do empty moves
    self.states = self.transitions.empty_move(self.states.clone());

    self.states = self.transitions.next_states(&self.states, symbol)
                                  .iter()
                                  .map(|state| { state.clone() }).collect();

    self.states = self.transitions.empty_move(self.states.clone());
  }

  pub fn accepted(&self) -> bool {
    !self.states.is_disjoint(self.accept_states)
  }
}

pub struct NFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: NFATransitions<S, T>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_nfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a nfa instance
  fn gen_nfa(&self) -> NFA<S, T> {
    let mut start_states = HashSet::new();
    start_states.insert(self.start_state.clone());
    NFA {
      states: start_states,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}
<|endoftext|>


<commit_before>mod attribute;
mod fact;
mod metric;
mod report;

pub use self::attribute::*;
pub use self::fact::*;
pub use self::metric::*;
pub use self::report::*;

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct MetadataMeta {
    pub author: Option<String>,
    pub uri: Option<String>,
    pub tags: Option<String>,
    pub created: Option<String>,
    pub identifier: Option<String>,
    pub deprecated: Option<String>,
    pub summary: Option<String>,
    pub isProduction: Option<u8>,
    pub title: Option<String>,
    pub category: Option<String>,
    pub updated: Option<String>,
    pub contributor: Option<String>,
}

impl MetadataMeta {
    pub fn identifier(&self) -> &Option<String> {
        &self.identifier
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct MetadataPaging {
    pub next: Option<String>,
    pub count: Option<u32>,
    pub offset: Option<u32>,
}
<commit_msg>WIP: Adding report_definition<commit_after>mod attribute;
mod fact;
mod metric;
mod report;
mod report_definition;

pub use self::attribute::*;
pub use self::fact::*;
pub use self::metric::*;
pub use self::report::*;
pub use self::report_definition::*;

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct MetadataMeta {
    pub author: Option<String>,
    pub uri: Option<String>,
    pub tags: Option<String>,
    pub created: Option<String>,
    pub identifier: Option<String>,
    pub deprecated: Option<String>,
    pub summary: Option<String>,
    pub isProduction: Option<u8>,
    pub title: Option<String>,
    pub category: Option<String>,
    pub updated: Option<String>,
    pub contributor: Option<String>,
}

impl MetadataMeta {
    pub fn identifier(&self) -> &Option<String> {
        &self.identifier
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct MetadataPaging {
    pub next: Option<String>,
    pub count: Option<u32>,
    pub offset: Option<u32>,
}
<|endoftext|>