<commit_before>//! A memory allocation arena specialized for types implement Copy.
//!
//! An `Arena` can allocate objects more efficiently than a
//! general-purpose allocator, but the objects cannot be
//! deallocated until the `Arena` itself is destroyed.
//!
//! To actually allocate out of an `Arena` after creating it,
//! use its `allocator()` method to create an `Allocator`.
//!
//! # Examples
//!
//! ```
//! use copy_arena::Arena;
//!
//! let mut arena = Arena::new();
//! let mut allocator = arena.allocator();
//!
//! let a: &mut i32 = allocator.alloc(5);
//! let b: &mut f64 = allocator.alloc_default();
//! let c: &mut [u8] = allocator.alloc_slice(b"some text");
//! let b: &mut [usize] = allocator.alloc_slice_fn(10, |idx| idx + 1);
//! let e: &mut [u32] = allocator.alloc_slice_default(10);
//! ```

use std::mem;
use std::cmp;
use std::usize;
use std::default::Default;
use std::slice;
use std::fmt;

struct Chunk {
    data: Vec<u8>,
    next: Option<Box<Chunk>>,
}

impl Chunk {
    fn attempt_alloc(&mut self, size: usize, align: usize) -> Option<*mut u8> {
        let start = round_up(self.data.len(), align);

        if size <= self.data.capacity() && start <= self.data.capacity() - size {
            Some(unsafe {
                self.data.set_len(start + size);
                self.data.as_mut_ptr().offset(start as isize)
            })
        } else {
            None
        }
    }
}

/// Holds the backing memory for allocated objects out of itself.
///
/// Actual allocation into the `Arena` happens via an `Allocator` returned
/// from `allocator()`.
pub struct Arena {
    head: Chunk,
}

impl Arena {
    /// Construct a new Arena. This _does_ allocate an block of memory.
    pub fn new() -> Arena {
        Arena::with_capacity(1000)
    }

    /// Construct a new Arena with the given initial capacity.
    ///
    /// The chosen capacity does not limit the final size of the arena.
    pub fn with_capacity(capacity: usize) -> Arena {
        Arena {
            head: Chunk{
                data: Vec::with_capacity(capacity),
                next: None,
            }
        }
    }

    fn add_chunk(&mut self, chunk_size: usize) {
        let mut new_head = Chunk {
            data: Vec::with_capacity(chunk_size),
            next: None,
        };

        mem::swap(&mut self.head, &mut new_head);
        self.head.next = Some(Box::new(new_head));
    }

    /// Construct an Allocator for this arena.
    pub fn allocator(&mut self) -> Allocator {
        Allocator {
            arena: self
        }
    }

    /// Get the number of bytes of memory that have been allocated
    /// in service of this arena. Not all of this capacity is necessarily
    /// useful, since asked-for memory may not perfectly fit in the
    /// underlying blocks allocated.
    pub fn capacity(&self) -> usize {
        let mut iter: &Chunk = &self.head;
        let mut total_capacity = 0;
        loop {
            total_capacity += iter.data.capacity();
            match iter.next {
                None => { return total_capacity; }
                Some(ref next) => { iter = next; }
            }
        }
    }
}

impl fmt::Debug for Arena {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Arena {{ capacity_bytes: {} }}", self.capacity()))
    }
}

/// Allows allocation out of arena.
#[derive(Debug)]
pub struct Allocator<'a> {
    arena: &'a mut Arena,
}

#[inline]
fn round_up(base: usize, align: usize) -> usize {
    (base + (align - 1)) & !(align - 1)
}

impl<'a> Allocator<'a> {
    fn alloc_raw(&mut self, size: usize, align: usize) -> &'a mut u8 {
        loop {
            match self.arena.head.attempt_alloc(size, align) {
                Some(x) => { return unsafe { mem::transmute(x) } },
                None => {
                    // Double the current allocation (or the asked for one), but don't overflow.
                    let minimum_reasonable = cmp::max(self.arena.head.data.len(), size);
                    let new_chunk_size = 2 * cmp::min(minimum_reasonable, usize::MAX/2);
                    self.arena.add_chunk(new_chunk_size);
                }
            }
        }
    }

    /// Allocate a copy of an object
    pub fn alloc<T: Copy>(&mut self, elem: T) -> &'a mut T {
        let memory = self.alloc_raw(mem::size_of::<T>(), mem::min_align_of::<T>());
        let res: &'a mut T = unsafe { mem::transmute(memory) };
        *res = elem;
        res
    }

    /// Allocate a default-valued object
    pub fn alloc_default<T: Copy+Default>(&mut self) -> &'a mut T {
        self.alloc(Default::default())
    }

    /// Allocate and leave uninitialized a slice of the given length
    fn alloc_slice_raw<T>(&mut self, len: usize) -> &'a mut [T] {
        let element_size = cmp::max(mem::size_of::<T>(), mem::min_align_of::<T>());
        assert_eq!(mem::size_of::<[T;7]>(), 7 * element_size);
        let byte_count = element_size.checked_mul(len).expect("Arena slice size overflow");
        let memory = self.alloc_raw(byte_count, mem::min_align_of::<T>());
        let res: &'a mut [T] = unsafe { slice::from_raw_parts_mut( mem::transmute(memory), len) };
        res
    }

    /// Allocate a copy of a slice
    pub fn alloc_slice<T: Copy>(&mut self, elems: &[T]) -> &'a mut [T] {
        let mut slice = self.alloc_slice_raw(elems.len());
        for (dest, src) in slice.iter_mut().zip(elems.iter()) {
            *dest = *src;
        }
        slice
    }

    /// Allocate and populate a slice, creating each element as a function
    /// of its index.
    pub fn alloc_slice_fn<T: Copy, F>(&mut self, len: usize, mut f: F)-> &'a mut [T]
        where F: FnMut(usize) -> T
    {
        let mut slice = self.alloc_slice_raw(len);
        for (idx, dest) in slice.iter_mut().enumerate() {
            *dest = f(idx)
        }
        slice
    }

    /// Allocate a slice populated by default-valued elements.
    pub fn alloc_slice_default<T: Copy+Default>(&mut self, len: usize)-> &'a mut [T] {
        self.alloc_slice_fn(len, |_| Default::default())
    }
}

#[test]
fn construct_simple() {
    let mut arena = Arena::with_capacity(4);
    let mut allocator = arena.allocator();

    let x: &mut i32 = allocator.alloc(44);
    let y: &mut u8 = allocator.alloc(3);
    let z: &mut u32 = allocator.alloc(0x11223344);
    let w: &mut f64 = allocator.alloc_default();
    assert_eq!(*x, 44);
    assert_eq!(*y, 3);
    assert_eq!(*z, 0x11223344);
    assert_eq!(*w, 0.0);
}

#[test]
fn just_enough_capacity() {
    let mut arena = Arena::with_capacity(7);
    arena.allocator().alloc_slice_default::<u8>(7);

    assert!(arena.head.next.is_none());
    assert_eq!(arena.head.data.len(), 7);
}

#[test]
fn barely_too_little_capacity() {
    let mut arena = Arena::with_capacity(7);
    arena.allocator().alloc_slice_default::<u8>(8);

    assert!(arena.head.next.is_some());
    assert_eq!(arena.head.data.len(), 8);
}

#[test]
fn many_u8s() {
    let mut arena = Arena::with_capacity(52);
    for i in 0..100 {
        assert_eq!(*arena.allocator().alloc(4), 4u8);
        assert_eq!(arena.head.data.len(), (i % 52) + 1);
    }
    assert!(arena.head.data.capacity() > 52);
}

#[test]
fn zero_capacity() {
    let mut arena = Arena::with_capacity(0);
    assert_eq!(arena.head.data.capacity(), 0);

    assert_eq!(*arena.allocator().alloc(9u32), 9u32);

    assert!(arena.head.data.capacity()>=4);
    assert!(arena.head.data.len()==4);
}

#[test]
fn surprisingly_large() {
    // Make sure asking for an allocation that is larger than the
    // block we otherwise would have allocated works fine.
    let mut arena = Arena::with_capacity(10);

    {
        let mut allocator = arena.allocator();
        let x = allocator.alloc(7u32);
        let ys : &[u8] = allocator.alloc_slice_default(600);

        assert_eq!(*x, 7u32);
        assert_eq!(ys.len(), 600);
    }

    assert!(arena.head.next.is_some());
    assert!(arena.head.data.capacity() >= 600);
    assert_eq!(arena.head.data.len(), 600);
}

#[test]
fn construct_slices() {
    let mut arena = Arena::with_capacity(4);
    let mut allocator = arena.allocator();

    let s = ::std::str::from_utf8(allocator.alloc_slice(b"abc")).unwrap();
    let xs: &[i32] = allocator.alloc_slice_fn(10, |idx| (idx as i32)*7);
    let ys: &[u64] = allocator.alloc_slice_default(4);

    assert_eq!(xs[9], 9*7);
    assert_eq!(s, "abc");
    assert_eq!(ys[0], 0);
}

#[cfg(test)]
mod tree {
    use super::{Arena, Allocator};

    #[derive(Copy, Clone)]
    struct Tree<'a> {
        left: Option<&'a Tree<'a>>,
        right: Option<&'a Tree<'a>>,
        content: u32
    }

    fn build_little_tree<'a>(allocator: &mut Allocator<'a>) -> &'a Tree<'a> {
        let left = allocator.alloc(Tree { left: None, right: None, content: 8 });
        let right = allocator.alloc(Tree { left: None, right: None, content: 16 });
        let parent = allocator.alloc(Tree { left: Some(left), right: Some(right), content: 13 });

        parent
    }

    #[test]
    fn make_tree() {
        let mut arena = Arena::new();
        let mut allocator = arena.allocator();

        let root = build_little_tree(&mut allocator);
        assert_eq!(root.content, 13);
        assert_eq!(root.left.unwrap().content, 8);
        assert_eq!(root.right.unwrap().content, 16);
    }

}

<commit_msg>Add (more complicated) tree example<commit_after>//! A memory allocation arena specialized for types implement Copy.
//!
//! An `Arena` can allocate objects more efficiently than a
//! general-purpose allocator, but the objects cannot be
//! deallocated until the `Arena` itself is destroyed.
//!
//! To actually allocate out of an `Arena` after creating it,
//! use its `allocator()` method to create an `Allocator`.
//!
//! # Examples
//!
//! Basic usage works as follows:
//!
//! ```
//! use copy_arena::Arena;
//!
//! let mut arena = Arena::new();
//! let mut allocator = arena.allocator();
//!
//! let a: &mut i32 = allocator.alloc(5);
//! let b: &mut f64 = allocator.alloc_default();
//! let c: &mut [u8] = allocator.alloc_slice(b"some text");
//! let b: &mut [usize] = allocator.alloc_slice_fn(10, |idx| idx + 1);
//! let e: &mut [u32] = allocator.alloc_slice_default(10);
//! ```
//!
//! A slightly more realistic use case would be to create a tree without
//! allocating from the heap for each node.
//!
//! ```
//! use copy_arena::{Arena, Allocator};
//!
//! #[derive(Copy, Clone)]
//! struct Tree<'a> {
//!     left: Option<&'a Tree<'a>>,
//!     right: Option<&'a Tree<'a>>,
//!     content: u32
//! }
//!
//! fn build_little_tree<'a>(allocator: &mut Allocator<'a>) -> &'a Tree<'a> {
//!     let left = allocator.alloc(Tree { left: None, right: None, content: 8 });
//!     let right = allocator.alloc(Tree { left: None, right: None, content: 16 });
//!     let parent = allocator.alloc(Tree { left: Some(left), right: Some(right), content: 13 });
//!
//!     parent
//! }
//!
//!
//! let mut arena = Arena::new();
//! let mut allocator = arena.allocator();
//!
//! let root = build_little_tree(&mut allocator);
//! assert_eq!(root.content, 13);
//! assert_eq!(root.left.unwrap().content, 8);
//! assert_eq!(root.right.unwrap().content, 16);
//!
//! ```

use std::mem;
use std::cmp;
use std::usize;
use std::default::Default;
use std::slice;
use std::fmt;

struct Chunk {
    data: Vec<u8>,
    next: Option<Box<Chunk>>,
}

impl Chunk {
    fn attempt_alloc(&mut self, size: usize, align: usize) -> Option<*mut u8> {
        let start = round_up(self.data.len(), align);

        if size <= self.data.capacity() && start <= self.data.capacity() - size {
            Some(unsafe {
                self.data.set_len(start + size);
                self.data.as_mut_ptr().offset(start as isize)
            })
        } else {
            None
        }
    }
}

/// Holds the backing memory for allocated objects out of itself.
///
/// Actual allocation into the `Arena` happens via an `Allocator` returned
/// from `allocator()`.
pub struct Arena {
    head: Chunk,
}

impl Arena {
    /// Construct a new Arena. This _does_ allocate an block of memory.
    pub fn new() -> Arena {
        Arena::with_capacity(1000)
    }

    /// Construct a new Arena with the given initial capacity.
    ///
    /// The chosen capacity does not limit the final size of the arena.
    pub fn with_capacity(capacity: usize) -> Arena {
        Arena {
            head: Chunk{
                data: Vec::with_capacity(capacity),
                next: None,
            }
        }
    }

    fn add_chunk(&mut self, chunk_size: usize) {
        let mut new_head = Chunk {
            data: Vec::with_capacity(chunk_size),
            next: None,
        };

        mem::swap(&mut self.head, &mut new_head);
        self.head.next = Some(Box::new(new_head));
    }

    /// Construct an Allocator for this arena.
    pub fn allocator(&mut self) -> Allocator {
        Allocator {
            arena: self
        }
    }

    /// Get the number of bytes of memory that have been allocated
    /// in service of this arena. Not all of this capacity is necessarily
    /// useful, since asked-for memory may not perfectly fit in the
    /// underlying blocks allocated.
    pub fn capacity(&self) -> usize {
        let mut iter: &Chunk = &self.head;
        let mut total_capacity = 0;
        loop {
            total_capacity += iter.data.capacity();
            match iter.next {
                None => { return total_capacity; }
                Some(ref next) => { iter = next; }
            }
        }
    }
}

impl fmt::Debug for Arena {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Arena {{ capacity_bytes: {} }}", self.capacity()))
    }
}

/// Allows allocation out of arena.
#[derive(Debug)]
pub struct Allocator<'a> {
    arena: &'a mut Arena,
}

#[inline]
fn round_up(base: usize, align: usize) -> usize {
    (base + (align - 1)) & !(align - 1)
}

impl<'a> Allocator<'a> {
    fn alloc_raw(&mut self, size: usize, align: usize) -> &'a mut u8 {
        loop {
            match self.arena.head.attempt_alloc(size, align) {
                Some(x) => { return unsafe { mem::transmute(x) } },
                None => {
                    // Double the current allocation (or the asked for one), but don't overflow.
                    let minimum_reasonable = cmp::max(self.arena.head.data.len(), size);
                    let new_chunk_size = 2 * cmp::min(minimum_reasonable, usize::MAX/2);
                    self.arena.add_chunk(new_chunk_size);
                }
            }
        }
    }

    /// Allocate a copy of an object
    pub fn alloc<T: Copy>(&mut self, elem: T) -> &'a mut T {
        let memory = self.alloc_raw(mem::size_of::<T>(), mem::min_align_of::<T>());
        let res: &'a mut T = unsafe { mem::transmute(memory) };
        *res = elem;
        res
    }

    /// Allocate a default-valued object
    pub fn alloc_default<T: Copy+Default>(&mut self) -> &'a mut T {
        self.alloc(Default::default())
    }

    /// Allocate and leave uninitialized a slice of the given length
    fn alloc_slice_raw<T>(&mut self, len: usize) -> &'a mut [T] {
        let element_size = cmp::max(mem::size_of::<T>(), mem::min_align_of::<T>());
        assert_eq!(mem::size_of::<[T;7]>(), 7 * element_size);
        let byte_count = element_size.checked_mul(len).expect("Arena slice size overflow");
        let memory = self.alloc_raw(byte_count, mem::min_align_of::<T>());
        let res: &'a mut [T] = unsafe { slice::from_raw_parts_mut( mem::transmute(memory), len) };
        res
    }

    /// Allocate a copy of a slice
    pub fn alloc_slice<T: Copy>(&mut self, elems: &[T]) -> &'a mut [T] {
        let mut slice = self.alloc_slice_raw(elems.len());
        for (dest, src) in slice.iter_mut().zip(elems.iter()) {
            *dest = *src;
        }
        slice
    }

    /// Allocate and populate a slice, creating each element as a function
    /// of its index.
    pub fn alloc_slice_fn<T: Copy, F>(&mut self, len: usize, mut f: F)-> &'a mut [T]
        where F: FnMut(usize) -> T
    {
        let mut slice = self.alloc_slice_raw(len);
        for (idx, dest) in slice.iter_mut().enumerate() {
            *dest = f(idx)
        }
        slice
    }

    /// Allocate a slice populated by default-valued elements.
    pub fn alloc_slice_default<T: Copy+Default>(&mut self, len: usize)-> &'a mut [T] {
        self.alloc_slice_fn(len, |_| Default::default())
    }
}

#[test]
fn construct_simple() {
    let mut arena = Arena::with_capacity(4);
    let mut allocator = arena.allocator();

    let x: &mut i32 = allocator.alloc(44);
    let y: &mut u8 = allocator.alloc(3);
    let z: &mut u32 = allocator.alloc(0x11223344);
    let w: &mut f64 = allocator.alloc_default();
    assert_eq!(*x, 44);
    assert_eq!(*y, 3);
    assert_eq!(*z, 0x11223344);
    assert_eq!(*w, 0.0);
}

#[test]
fn just_enough_capacity() {
    let mut arena = Arena::with_capacity(7);
    arena.allocator().alloc_slice_default::<u8>(7);

    assert!(arena.head.next.is_none());
    assert_eq!(arena.head.data.len(), 7);
}

#[test]
fn barely_too_little_capacity() {
    let mut arena = Arena::with_capacity(7);
    arena.allocator().alloc_slice_default::<u8>(8);

    assert!(arena.head.next.is_some());
    assert_eq!(arena.head.data.len(), 8);
}

#[test]
fn many_u8s() {
    let mut arena = Arena::with_capacity(52);
    for i in 0..100 {
        assert_eq!(*arena.allocator().alloc(4), 4u8);
        assert_eq!(arena.head.data.len(), (i % 52) + 1);
    }
    assert!(arena.head.data.capacity() > 52);
}

#[test]
fn zero_capacity() {
    let mut arena = Arena::with_capacity(0);
    assert_eq!(arena.head.data.capacity(), 0);

    assert_eq!(*arena.allocator().alloc(9u32), 9u32);

    assert!(arena.head.data.capacity()>=4);
    assert!(arena.head.data.len()==4);
}

#[test]
fn surprisingly_large() {
    // Make sure asking for an allocation that is larger than the
    // block we otherwise would have allocated works fine.
    let mut arena = Arena::with_capacity(10);

    {
        let mut allocator = arena.allocator();
        let x = allocator.alloc(7u32);
        let ys : &[u8] = allocator.alloc_slice_default(600);

        assert_eq!(*x, 7u32);
        assert_eq!(ys.len(), 600);
    }

    assert!(arena.head.next.is_some());
    assert!(arena.head.data.capacity() >= 600);
    assert_eq!(arena.head.data.len(), 600);
}

#[test]
fn construct_slices() {
    let mut arena = Arena::with_capacity(4);
    let mut allocator = arena.allocator();

    let s = ::std::str::from_utf8(allocator.alloc_slice(b"abc")).unwrap();
    let xs: &[i32] = allocator.alloc_slice_fn(10, |idx| (idx as i32)*7);
    let ys: &[u64] = allocator.alloc_slice_default(4);

    assert_eq!(xs[9], 9*7);
    assert_eq!(s, "abc");
    assert_eq!(ys[0], 0);
}

#[cfg(test)]
mod tree {
    use super::{Arena, Allocator};

    #[derive(Copy, Clone)]
    struct Tree<'a> {
        left: Option<&'a Tree<'a>>,
        right: Option<&'a Tree<'a>>,
        content: u32
    }

    fn build_little_tree<'a>(allocator: &mut Allocator<'a>) -> &'a Tree<'a> {
        let left = allocator.alloc(Tree { left: None, right: None, content: 8 });
        let right = allocator.alloc(Tree { left: None, right: None, content: 16 });
        let parent = allocator.alloc(Tree { left: Some(left), right: Some(right), content: 13 });

        parent
    }

    #[test]
    fn make_tree() {
        let mut arena = Arena::new();
        let mut allocator = arena.allocator();

        let root = build_little_tree(&mut allocator);
        assert_eq!(root.content, 13);
        assert_eq!(root.left.unwrap().content, 8);
        assert_eq!(root.right.unwrap().content, 16);
    }

}

<|endoftext|>


<commit_before>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! OpenStack Client in Rust.
//!
//! The goal of this project is to provide a simple API for working with
//! OpenStack clouds.
//!
//! * [Authentication](auth/index.html)
//! * [High-level API](struct.Cloud.html)
//!
//! API-specific notes:
//!
//! * [Compute API support](compute/index.html)

#![crate_name = "openstack"]
#![crate_type = "lib"]
// NOTE: we do not use generic deny(warnings) to avoid breakages with new
// versions of the compiler. Add more warnings here as you discover them.
// Taken from https://github.com/rust-unofficial/patterns/
#![deny(const_err,
        dead_code,
        extra_requirement_in_impl,
        improper_ctypes,
        legacy_directory_ownership,
        missing_copy_implementations,
        missing_debug_implementations,
        missing_docs,
        non_shorthand_field_patterns,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements ,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        safe_extern_statics,
        trivial_casts,
        trivial_numeric_casts,
        unconditional_recursion,
        unions_with_drop_fields,
        unsafe_code,
        unused,
        unused_allocation,
        unused_comparisons,
        unused_doc_comment,
        unused_extern_crates,
        unused_import_braces,
        unused_parens,
        unused_qualifications,
        unused_results,
        while_true)]

#[cfg(feature = "compute")]
extern crate chrono;
#[macro_use]
extern crate log;
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[allow(unused_extern_crates)]
extern crate serde_json;

pub mod auth;
mod cloud;
mod common;
#[cfg(feature = "compute")]
pub mod compute;
mod identity;
pub mod service;
pub mod session;
mod utils;

pub use cloud::Cloud;
pub use common::Error;
pub use common::Result;
pub use common::ApiVersion;
pub use common::ApiVersionRequest;
pub use common::Sort;
<commit_msg>chore: remove extra_requirement_in_impl lint, it's an error now<commit_after>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! OpenStack Client in Rust.
//!
//! The goal of this project is to provide a simple API for working with
//! OpenStack clouds.
//!
//! * [Authentication](auth/index.html)
//! * [High-level API](struct.Cloud.html)
//!
//! API-specific notes:
//!
//! * [Compute API support](compute/index.html)

#![crate_name = "openstack"]
#![crate_type = "lib"]
// NOTE: we do not use generic deny(warnings) to avoid breakages with new
// versions of the compiler. Add more warnings here as you discover them.
// Taken from https://github.com/rust-unofficial/patterns/
#![deny(const_err,
        dead_code,
        improper_ctypes,
        legacy_directory_ownership,
        missing_copy_implementations,
        missing_debug_implementations,
        missing_docs,
        non_shorthand_field_patterns,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements ,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        safe_extern_statics,
        trivial_casts,
        trivial_numeric_casts,
        unconditional_recursion,
        unions_with_drop_fields,
        unsafe_code,
        unused,
        unused_allocation,
        unused_comparisons,
        unused_doc_comment,
        unused_extern_crates,
        unused_import_braces,
        unused_parens,
        unused_qualifications,
        unused_results,
        while_true)]

#[cfg(feature = "compute")]
extern crate chrono;
#[macro_use]
extern crate log;
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[allow(unused_extern_crates)]
extern crate serde_json;

pub mod auth;
mod cloud;
mod common;
#[cfg(feature = "compute")]
pub mod compute;
mod identity;
pub mod service;
pub mod session;
mod utils;

pub use cloud::Cloud;
pub use common::Error;
pub use common::Result;
pub use common::ApiVersion;
pub use common::ApiVersionRequest;
pub use common::Sort;
<|endoftext|>


<commit_before>// `encode` and `decode` are used instead of `ser` and `de` to avoid confusion with the serder
// Serializer and Deserializer traits which occupy a similar namespace.
mod cow_iter;
pub mod decode;
pub mod encode;
mod into_cow;

pub use crate::decode::Deserializer;
pub use crate::encode::Serializer;
pub use crate::into_cow::IntoCow;

/// Use serde Deserialize to build `T` from a `redis::Value`
pub fn from_redis_value<'de, T, RV>(rv: RV) -> decode::Result<T>
where
    T: serde::de::Deserialize<'de>,
    RV: IntoCow<'de>,
{
    let value = rv.into_cow();
    serde::de::Deserialize::deserialize(Deserializer::new(value))
}

pub trait RedisDeserialize<'de, T>
where
    T: serde::de::Deserialize<'de>,
{
    fn deserialize(&'de self) -> decode::Result<T>;
}

impl<'de, T> RedisDeserialize<'de, T> for redis::Value
where
    T: serde::de::Deserialize<'de>,
{
    fn deserialize(&'de self) -> decode::Result<T> {
        serde::de::Deserialize::deserialize(Deserializer::new(self))
    }
}

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

    #[test]
    fn chain_deserialize_works() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = v.deserialize().unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }

    #[test]
    fn from_redis_value_works_with_owned() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = from_redis_value(v).unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }

    #[test]
    fn from_redis_value_works_with_borrow() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = from_redis_value(&v).unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }
}
<commit_msg>Use seperate input lifetimes for deserializer & rv<commit_after>// `encode` and `decode` are used instead of `ser` and `de` to avoid confusion with the serder
// Serializer and Deserializer traits which occupy a similar namespace.
mod cow_iter;
pub mod decode;
pub mod encode;
mod into_cow;

pub use crate::decode::Deserializer;
pub use crate::encode::Serializer;
pub use crate::into_cow::IntoCow;

/// Use serde Deserialize to build `T` from a `redis::Value`
pub fn from_redis_value<'a, 'de, T, RV>(rv: RV) -> decode::Result<T>
where
    T: serde::de::Deserialize<'de>,
    RV: IntoCow<'a>,
{
    let value = rv.into_cow();
    serde::de::Deserialize::deserialize(Deserializer::new(value))
}

pub trait RedisDeserialize<'de, T>
where
    T: serde::de::Deserialize<'de>,
{
    fn deserialize(&'de self) -> decode::Result<T>;
}

impl<'de, T> RedisDeserialize<'de, T> for redis::Value
where
    T: serde::de::Deserialize<'de>,
{
    fn deserialize(&'de self) -> decode::Result<T> {
        serde::de::Deserialize::deserialize(Deserializer::new(self))
    }
}

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

    #[test]
    fn chain_deserialize_works() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = v.deserialize().unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }

    #[test]
    fn from_redis_value_works_with_owned() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = from_redis_value(v).unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }

    #[test]
    fn from_redis_value_works_with_borrow() {
        let v = Value::Bulk(vec![Value::Int(5), Value::Data(b"hello".to_vec())]);

        let actual: (u8, String) = from_redis_value(&v).unwrap();
        let expected = (5, "hello".into());

        assert_eq!(expected, actual);
    }
}
<|endoftext|>


<commit_before>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let [] $($body:tt)*)) => {{
        $(lisp!($body));*
    }};
    ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $arg:tt) => { &lisp!($arg) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $arg:tt) => { *lisp!($arg) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list (:: $($name:tt)*), . $(, ($member:ident $val:tt))*) => {
        $($name)* { $($member: lisp!($val))* }
    };
    (@list $name:ident, . $(, ($member:ident $val:tt))*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list (:: $name:path) $(, $arg:tt),*) => {
        $name($(lisp!($arg)),*)
    };
    (@list $name:expr $(, $arg:tt)*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // method calls
    (@list ., $name:ident, $subj:tt $(, $arg:tt)*) => {
        lisp!($subj).$name($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<commit_msg>lambda args in square brackets<commit_after>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda [$($argn:ident)*] $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* }
        $s
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let [] $($body:tt)*)) => {{
        $(lisp!($body));*
    }};
    ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $arg:tt) => { &lisp!($arg) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $arg:tt) => { *lisp!($arg) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list (:: $($name:tt)*), . $(, ($member:ident $val:tt))*) => {
        $($name)* { $($member: lisp!($val))* }
    };
    (@list $name:ident, . $(, ($member:ident $val:tt))*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list (:: $name:path) $(, $arg:tt),*) => {
        $name($(lisp!($arg)),*)
    };
    (@list $name:expr $(, $arg:tt)*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // method calls
    (@list ., $name:ident, $subj:tt $(, $arg:tt)*) => {
        lisp!($subj).$name($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<|endoftext|>


<commit_before>// use std::marker::PhantomData;
// use std::slice;

pub struct StrCursor<'a> {
    s: &'a str,
    at: *const u8,
}

impl<'a> StrCursor<'a> {
    pub fn new_at_start(s: &'a str) -> StrCursor<'a> {
        StrCursor {
            s: s,
            at: s.as_ptr(),
        }
    }

    pub fn new_at_end(s: &'a str) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: s.as_ptr().offset(s.len() as isize),
            }
        }
    }

    pub fn new_left_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_left(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn new_right_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_right(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn at_prev_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_left() {
            true => Some(self),
            false => None
        }
    }

    pub fn at_next_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_right() {
            true => Some(self),
            false => None
        }
    }

    pub fn seek_prev_cp(&mut self) {
        if !self.try_seek_left() {
            panic!("cannot seek past the beginning of a string");
        }
    }

    pub fn seek_next_cp(&mut self) {
        if !self.try_seek_right() {
            panic!("cannot seek past the end of a string");
        }
    }

    pub fn slice_before(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(0, self.byte_pos())
        }
    }

    pub fn slice_after(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(self.byte_pos(), self.s.len())
        }
    }

    pub fn byte_pos(&self) -> usize {
        self.at as usize - self.s.as_ptr() as usize
    }

    fn try_seek_left(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == 0 {
                return false;
            }
            self.at = seek_utf8_cp_start_left(self.s, self.at.offset(-1));
            true
        }
    }

    fn try_seek_right(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == self.s.len() {
                return false;
            }
            self.at = seek_utf8_cp_start_right(self.s, self.at.offset(1));
            true
        }
    }
}

impl<'a> Copy for StrCursor<'a> {}

impl<'a> Clone for StrCursor<'a> {
    fn clone(&self) -> StrCursor<'a> {
        *self
    }
}

impl<'a> std::fmt::Debug for StrCursor<'a> {
	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
    }
}

#[cfg(test)]
#[test]
fn test_new_at_start() {
    let cur = StrCursor::new_at_start("abcdef");
    assert_eq!(cur.slice_before(), "");
    assert_eq!(cur.slice_after(), "abcdef");
}

#[cfg(test)]
#[test]
fn test_new_at_end() {
    let cur = StrCursor::new_at_end("abcdef");
    assert_eq!(cur.slice_before(), "abcdef");
    assert_eq!(cur.slice_after(), "");
}

#[cfg(test)]
#[test]
fn test_new_left_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_left_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a ");
    assert_eq!(cur.slice_after(), "本当 test.");
}

#[cfg(test)]
#[test]
fn test_new_right_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_right_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a 本");
    assert_eq!(cur.slice_after(), "当 test.");
}

#[cfg(test)]
#[test]
fn test_at_prev_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_end(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_prev_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![14, 10, 9, 6, 3, 0]);
}

#[cfg(test)]
#[test]
fn test_at_next_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_next_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![3, 6, 9, 10, 14, 17]);
}

unsafe fn seek_utf8_cp_start_left(s: &str, mut from: *const u8) -> *const u8 {
    let beg = s.as_ptr();
    while from > beg && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(-1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_left() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[1]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[2]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[4]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[5]) }, &b[3]);
}

unsafe fn seek_utf8_cp_start_right(s: &str, mut from: *const u8) -> *const u8 {
    let end = s.as_ptr().offset(s.len() as isize);
    while from < end && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_right() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[1]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[2]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[4]) }, &b[6]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[5]) }, &b[6]);
}

#[cfg(test)]
mod test_util {
    pub struct FiniteIter<T, F>(Option<T>, F);

    impl<T, F> Iterator for FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate<T, F>(seed: T, f: F) -> FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIter(Some(seed), f)
    }
}<commit_msg>Added char_before, char_after.<commit_after>// use std::marker::PhantomData;
// use std::slice;

pub struct StrCursor<'a> {
    s: &'a str,
    at: *const u8,
}

impl<'a> StrCursor<'a> {
    pub fn new_at_start(s: &'a str) -> StrCursor<'a> {
        StrCursor {
            s: s,
            at: s.as_ptr(),
        }
    }

    pub fn new_at_end(s: &'a str) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: s.as_ptr().offset(s.len() as isize),
            }
        }
    }

    pub fn new_left_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_left(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn new_right_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_right(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn at_prev_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_left() {
            true => Some(self),
            false => None
        }
    }

    pub fn at_next_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_right() {
            true => Some(self),
            false => None
        }
    }

    pub fn seek_prev_cp(&mut self) {
        if !self.try_seek_left() {
            panic!("cannot seek past the beginning of a string");
        }
    }

    pub fn seek_next_cp(&mut self) {
        if !self.try_seek_right() {
            panic!("cannot seek past the end of a string");
        }
    }

    pub fn slice_before(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(0, self.byte_pos())
        }
    }

    pub fn slice_after(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(self.byte_pos(), self.s.len())
        }
    }

    pub fn char_before(&self) -> Option<char> {
        self.at_prev_cp().and_then(|cur| cur.char_after())
    }

    pub fn char_after(&self) -> Option<char> {
        self.slice_after().chars().next()
    }

    pub fn byte_pos(&self) -> usize {
        self.at as usize - self.s.as_ptr() as usize
    }

    fn try_seek_left(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == 0 {
                return false;
            }
            self.at = seek_utf8_cp_start_left(self.s, self.at.offset(-1));
            true
        }
    }

    fn try_seek_right(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == self.s.len() {
                return false;
            }
            self.at = seek_utf8_cp_start_right(self.s, self.at.offset(1));
            true
        }
    }
}

impl<'a> Copy for StrCursor<'a> {}

impl<'a> Clone for StrCursor<'a> {
    fn clone(&self) -> StrCursor<'a> {
        *self
    }
}

impl<'a> std::fmt::Debug for StrCursor<'a> {
	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
    }
}

#[cfg(test)]
#[test]
fn test_new_at_start() {
    let cur = StrCursor::new_at_start("abcdef");
    assert_eq!(cur.slice_before(), "");
    assert_eq!(cur.slice_after(), "abcdef");
}

#[cfg(test)]
#[test]
fn test_new_at_end() {
    let cur = StrCursor::new_at_end("abcdef");
    assert_eq!(cur.slice_before(), "abcdef");
    assert_eq!(cur.slice_after(), "");
}

#[cfg(test)]
#[test]
fn test_new_left_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_left_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a ");
    assert_eq!(cur.slice_after(), "本当 test.");
}

#[cfg(test)]
#[test]
fn test_new_right_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_right_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a 本");
    assert_eq!(cur.slice_after(), "当 test.");
}

#[cfg(test)]
#[test]
fn test_at_prev_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_end(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_prev_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![14, 10, 9, 6, 3, 0]);
}

#[cfg(test)]
#[test]
fn test_at_next_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_next_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![3, 6, 9, 10, 14, 17]);
}

#[cfg(test)]
#[test]
fn test_char_before_and_after() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let r = test_util::finite_iterate_lead(cur, StrCursor::at_next_cp)
        .map(|cur| (cur.byte_pos(), cur.char_before(), cur.char_after()))
        .collect::<Vec<_>>();
    assert_eq!(r, vec![
        (0, None, Some('大')),
        (3, Some('大'), Some('嫌')),
        (6, Some('嫌'), Some('い')),
        (9, Some('い'), Some(',')),
        (10, Some(','), Some('💪')),
        (14, Some('💪'), Some('❤')),
        (17, Some('❤'), None)
    ]);
}

unsafe fn seek_utf8_cp_start_left(s: &str, mut from: *const u8) -> *const u8 {
    let beg = s.as_ptr();
    while from > beg && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(-1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_left() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[1]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[2]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[4]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[5]) }, &b[3]);
}

unsafe fn seek_utf8_cp_start_right(s: &str, mut from: *const u8) -> *const u8 {
    let end = s.as_ptr().offset(s.len() as isize);
    while from < end && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_right() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[1]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[2]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[4]) }, &b[6]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[5]) }, &b[6]);
}

#[cfg(test)]
mod test_util {
    pub struct FiniteIter<T, F>(Option<T>, F);

    impl<T, F> Iterator for FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate<T, F>(seed: T, f: F) -> FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIter(Some(seed), f)
    }
    pub struct FiniteIterLead<T, F>(Option<T>, F, bool);

    impl<T, F> Iterator for FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            if !self.2 {
                self.2 = true;
                return self.0.clone();
            }

            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate_lead<T, F>(seed: T, f: F) -> FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIterLead(Some(seed), f, false)
    }
}<|endoftext|>


<commit_before>#![feature(collections, io, path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<commit_msg>Remove unnecessary features and add new ones<commit_after>#![feature(collections, std_misc)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<|endoftext|>


<commit_before>#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals)]
extern crate libc;

use std::os::raw;
use std::sync::{Once, ONCE_INIT};

pub const MAX_OID_LEN:       libc::size_t = 128;

pub const STAT_SUCCESS:      raw::c_int = 0;
pub const STAT_ERROR:        raw::c_int = 1;
pub const STAT_TIMEOUT:      raw::c_int = 2;

pub const SNMP_VERSION_1:    raw::c_long = 0;
pub const SNMP_VERSION_2c:   raw::c_long = 1;
pub const SNMP_VERSION_3:    raw::c_long = 3;

pub const SNMP_SEC_LEVEL_NOAUTH:     raw::c_int = 1;
pub const SNMP_SEC_LEVEL_AUTHNOPRIV: raw::c_int = 2;
pub const SNMP_SEC_LEVEL_AUTHPRIV:   raw::c_int = 3;

pub const SNMP_MSG_GET:      raw::c_int = 160;
pub const SNMP_MSG_GETNEXT:  raw::c_int = 161;
pub const SNMP_MSG_RESPONSE: raw::c_int = 162;
pub const SNMP_MSG_SET:      raw::c_int = 163;
pub const SNMP_MSG_TRAP:     raw::c_int = 164;
pub const SNMP_MSG_GETBULK:  raw::c_int = 165;
pub const SNMP_MSG_INFORM:   raw::c_int = 166;
pub const SNMP_MSG_TRAP2:    raw::c_int = 167;
pub const SNMP_MSG_REPORT:   raw::c_int = 168;

pub const SNMP_NOSUCHOBJECT:     raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x0);
pub const SNMP_NOSUCHINSTANCE:   raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x1);
pub const SNMP_ENDOFMIBVIEW:     raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x2);

pub const SNMP_ERR_NOERROR:             raw::c_long =  0;
pub const SNMP_ERR_TOOBIG:	            raw::c_long =  1;
pub const SNMP_ERR_NOSUCHNAME:          raw::c_long =  2;
pub const SNMP_ERR_BADVALUE:            raw::c_long =  3;
pub const SNMP_ERR_READONLY:            raw::c_long =  4;
pub const SNMP_ERR_GENERR:	            raw::c_long =  5;
pub const SNMP_ERR_NOACCESS:	          raw::c_long =  6;
pub const SNMP_ERR_WRONGTYPE:	          raw::c_long =  7;
pub const SNMP_ERR_WRONGLENGTH:		      raw::c_long =  8;
pub const SNMP_ERR_WRONGENCODING:	      raw::c_long =  9;
pub const SNMP_ERR_WRONGVALUE:		      raw::c_long = 10;
pub const SNMP_ERR_NOCREATION:		      raw::c_long = 11;
pub const SNMP_ERR_INCONSISTENTVALUE:	  raw::c_long = 12;
pub const SNMP_ERR_RESOURCEUNAVAILABLE: raw::c_long = 13;
pub const SNMP_ERR_COMMITFAILED:        raw::c_long = 14;
pub const SNMP_ERR_UNDOFAILED:	        raw::c_long = 15;
pub const SNMP_ERR_AUTHORIZATIONERROR:  raw::c_long = 16;
pub const SNMP_ERR_NOTWRITABLE:         raw::c_long = 17;
pub const SNMP_ERR_INCONSISTENTNAME:    raw::c_long = 18;

pub const SNMPERR_SUCCESS:                      raw::c_int =   0;     /* XXX  Non-PDU "success" code. */
pub const SNMPERR_GENERR:                       raw::c_int =  -1;
pub const SNMPERR_BAD_LOCPORT:                  raw::c_int =  -2;
pub const SNMPERR_BAD_ADDRESS:                  raw::c_int =  -3;
pub const SNMPERR_BAD_SESSION:                  raw::c_int =  -4;
pub const SNMPERR_TOO_LONG:                     raw::c_int =  -5;
pub const SNMPERR_NO_SOCKET:                    raw::c_int =  -6;
pub const SNMPERR_V2_IN_V1:                     raw::c_int =  -7;
pub const SNMPERR_V1_IN_V2:                     raw::c_int =  -8;
pub const SNMPERR_BAD_REPEATERS:                raw::c_int =  -9;
pub const SNMPERR_BAD_REPETITIONS:              raw::c_int = -10;
pub const SNMPERR_BAD_ASN1_BUILD:               raw::c_int = -11;
pub const SNMPERR_BAD_SENDTO:                   raw::c_int = -12;
pub const SNMPERR_BAD_PARSE:                    raw::c_int = -13;
pub const SNMPERR_BAD_VERSION:                  raw::c_int = -14;
pub const SNMPERR_BAD_SRC_PARTY:                raw::c_int = -15;
pub const SNMPERR_BAD_DST_PARTY:                raw::c_int = -16;
pub const SNMPERR_BAD_CONTEXT:                  raw::c_int = -17;
pub const SNMPERR_BAD_COMMUNITY:                raw::c_int = -18;
pub const SNMPERR_NOAUTH_DESPRIV:               raw::c_int = -19;
pub const SNMPERR_BAD_ACL:                      raw::c_int = -20;
pub const SNMPERR_BAD_PARTY:                    raw::c_int = -21;
pub const SNMPERR_ABORT:                        raw::c_int = -22;
pub const SNMPERR_UNKNOWN_PDU:                  raw::c_int = -23;
pub const SNMPERR_TIMEOUT:                      raw::c_int = -24;
pub const SNMPERR_BAD_RECVFROM:                 raw::c_int = -25;
pub const SNMPERR_BAD_ENG_ID:                   raw::c_int = -26;
pub const SNMPERR_BAD_SEC_NAME:                 raw::c_int = -27;
pub const SNMPERR_BAD_SEC_LEVEL:                raw::c_int = -28;
pub const SNMPERR_ASN_PARSE_ERR:                raw::c_int = -29;
pub const SNMPERR_UNKNOWN_SEC_MODEL:            raw::c_int = -30;
pub const SNMPERR_INVALID_MSG:                  raw::c_int = -31;
pub const SNMPERR_UNKNOWN_ENG_ID:               raw::c_int = -32;
pub const SNMPERR_UNKNOWN_USER_NAME:            raw::c_int = -33;
pub const SNMPERR_UNSUPPORTED_SEC_LEVEL:        raw::c_int = -34;
pub const SNMPERR_AUTHENTICATION_FAILURE:       raw::c_int = -35;
pub const SNMPERR_NOT_IN_TIME_WINDOW:           raw::c_int = -36;
pub const SNMPERR_DECRYPTION_ERR:               raw::c_int = -37;
pub const SNMPERR_SC_GENERAL_FAILURE:           raw::c_int = -38;
pub const SNMPERR_SC_NOT_CONFIGURED:            raw::c_int = -39;
pub const SNMPERR_KT_NOT_AVAILABLE:             raw::c_int = -40;
pub const SNMPERR_UNKNOWN_REPORT:               raw::c_int = -41;
pub const SNMPERR_USM_GENERICERROR:             raw::c_int = -42;
pub const SNMPERR_USM_UNKNOWNSECURITYNAME:      raw::c_int = -43;
pub const SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL: raw::c_int = -44;
pub const SNMPERR_USM_ENCRYPTIONERROR:          raw::c_int = -45;
pub const SNMPERR_USM_AUTHENTICATIONFAILURE:    raw::c_int = -46;
pub const SNMPERR_USM_PARSEERROR:               raw::c_int = -47;
pub const SNMPERR_USM_UNKNOWNENGINEID:          raw::c_int = -48;
pub const SNMPERR_USM_NOTINTIMEWINDOW:          raw::c_int = -49;
pub const SNMPERR_USM_DECRYPTIONERROR:          raw::c_int = -50;
pub const SNMPERR_NOMIB:                        raw::c_int = -51;
pub const SNMPERR_RANGE:                        raw::c_int = -52;
pub const SNMPERR_MAX_SUBID:                    raw::c_int = -53;
pub const SNMPERR_BAD_SUBID:                    raw::c_int = -54;
pub const SNMPERR_LONG_OID:                     raw::c_int = -55;
pub const SNMPERR_BAD_NAME:                     raw::c_int = -56;
pub const SNMPERR_VALUE:                        raw::c_int = -57;
pub const SNMPERR_UNKNOWN_OBJID:                raw::c_int = -58;
pub const SNMPERR_NULL_PDU:                     raw::c_int = -59;
pub const SNMPERR_NO_VARS:                      raw::c_int = -60;
pub const SNMPERR_VAR_TYPE:                     raw::c_int = -61;
pub const SNMPERR_MALLOC:                       raw::c_int = -62;
pub const SNMPERR_KRB5:                         raw::c_int = -63;
pub const SNMPERR_PROTOCOL:                     raw::c_int = -64;
pub const SNMPERR_OID_NONINCREASING:            raw::c_int = -65;
pub const SNMPERR_JUST_A_CONTEXT_PROBE:         raw::c_int = -66;
pub const SNMPERR_TRANSPORT_NO_CONFIG:          raw::c_int = -67;
pub const SNMPERR_TRANSPORT_CONFIG_ERROR:       raw::c_int = -68;
pub const SNMPERR_TLS_NO_CERTIFICATE:           raw::c_int = -69;
pub const SNMPERR_MAX:                          raw::c_int = -69;

pub const ASN_BOOLEAN:	    raw::c_uchar = 0x01;
pub const ASN_INTEGER:	    raw::c_uchar = 0x02;
pub const ASN_BIT_STR:	    raw::c_uchar = 0x03;
pub const ASN_OCTET_STR:    raw::c_uchar = 0x04;
pub const ASN_NULL:	        raw::c_uchar = 0x05;
pub const ASN_OBJECT_ID:	  raw::c_uchar = 0x06;
pub const ASN_SEQUENCE:	    raw::c_uchar = 0x10;
pub const ASN_SET:		      raw::c_uchar = 0x11;
pub const ASN_UNIVERSAL:	  raw::c_uchar = 0x00;
pub const ASN_APPLICATION:  raw::c_uchar = 0x40;
pub const ASN_CONTEXT:	    raw::c_uchar = 0x80;
pub const ASN_PRIVATE:	    raw::c_uchar = 0xC0;
pub const ASN_PRIMITIVE:	  raw::c_uchar = 0x00;
pub const ASN_CONSTRUCTOR:	raw::c_uchar = 0x20;

pub const ASN_IPADDRESS:    raw::c_uchar = (ASN_APPLICATION |  0);
pub const ASN_COUNTER:      raw::c_uchar = (ASN_APPLICATION |  1);
pub const ASN_GAUGE:        raw::c_uchar = (ASN_APPLICATION |  2);
pub const ASN_UNSIGNED:     raw::c_uchar = (ASN_APPLICATION |  2); // RFC 1902 - same as GAUGE
pub const ASN_TIMETICKS:    raw::c_uchar = (ASN_APPLICATION |  3);
pub const ASN_OPAQUE:       raw::c_uchar = (ASN_APPLICATION |  4); // changed so no conflict with other includes
pub const ASN_NSAP:         raw::c_uchar = (ASN_APPLICATION |  5); // historic - don't use
pub const ASN_COUNTER64:    raw::c_uchar = (ASN_APPLICATION |  6);
pub const ASN_UINTEGER:     raw::c_uchar = (ASN_APPLICATION |  7); // historic - don't use
pub const ASN_FLOAT:        raw::c_uchar = (ASN_APPLICATION |  8);
pub const ASN_DOUBLE:       raw::c_uchar = (ASN_APPLICATION |  9);
pub const ASN_INTEGER64:    raw::c_uchar = (ASN_APPLICATION | 10);
pub const ASN_UNSIGNED64:   raw::c_uchar = (ASN_APPLICATION | 11);

pub const USM_AUTH_KU_LEN: usize = 32;
pub const USM_PRIV_KU_LEN: usize = 32;

mod auto;
pub use auto::*;

static INIT: Once = ONCE_INIT;

pub fn init(typ: &[u8]) {
    let mut type_dup = [0u8; 256];
    type_dup[..typ.len()].clone_from_slice(typ);
    unsafe {
        INIT.call_once(||{
            init_snmp(type_dup.as_ptr() as *mut raw::c_char);
            netsnmp_init_mib();
        })
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Add security model constants.<commit_after>#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals)]
extern crate libc;

use std::os::raw;
use std::sync::{Once, ONCE_INIT};

pub const MAX_OID_LEN:       libc::size_t = 128;

pub const STAT_SUCCESS:      raw::c_int = 0;
pub const STAT_ERROR:        raw::c_int = 1;
pub const STAT_TIMEOUT:      raw::c_int = 2;

pub const SNMP_VERSION_1:    raw::c_long = 0;
pub const SNMP_VERSION_2c:   raw::c_long = 1;
pub const SNMP_VERSION_3:    raw::c_long = 3;

pub const SNMP_SEC_MODEL_ANY:        raw::c_int = 0;
pub const SNMP_SEC_MODEL_SNMPv1:     raw::c_int = 1;
pub const SNMP_SEC_MODEL_SNMPv2c:    raw::c_int = 2;
pub const SNMP_SEC_MODEL_USM:        raw::c_int = 3;
pub const SNMP_SEC_MODEL_TSM:        raw::c_int = 4;
pub const SNMP_SEC_MODEL_SNMPv2p:    raw::c_int = 256;

pub const SNMP_SEC_LEVEL_NOAUTH:     raw::c_int = 1;
pub const SNMP_SEC_LEVEL_AUTHNOPRIV: raw::c_int = 2;
pub const SNMP_SEC_LEVEL_AUTHPRIV:   raw::c_int = 3;

pub const SNMP_MSG_GET:      raw::c_int = 160;
pub const SNMP_MSG_GETNEXT:  raw::c_int = 161;
pub const SNMP_MSG_RESPONSE: raw::c_int = 162;
pub const SNMP_MSG_SET:      raw::c_int = 163;
pub const SNMP_MSG_TRAP:     raw::c_int = 164;
pub const SNMP_MSG_GETBULK:  raw::c_int = 165;
pub const SNMP_MSG_INFORM:   raw::c_int = 166;
pub const SNMP_MSG_TRAP2:    raw::c_int = 167;
pub const SNMP_MSG_REPORT:   raw::c_int = 168;

pub const SNMP_NOSUCHOBJECT:     raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x0);
pub const SNMP_NOSUCHINSTANCE:   raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x1);
pub const SNMP_ENDOFMIBVIEW:     raw::c_uchar = (ASN_CONTEXT | ASN_PRIMITIVE | 0x2);

pub const SNMP_ERR_NOERROR:             raw::c_long =  0;
pub const SNMP_ERR_TOOBIG:	            raw::c_long =  1;
pub const SNMP_ERR_NOSUCHNAME:          raw::c_long =  2;
pub const SNMP_ERR_BADVALUE:            raw::c_long =  3;
pub const SNMP_ERR_READONLY:            raw::c_long =  4;
pub const SNMP_ERR_GENERR:	            raw::c_long =  5;
pub const SNMP_ERR_NOACCESS:	          raw::c_long =  6;
pub const SNMP_ERR_WRONGTYPE:	          raw::c_long =  7;
pub const SNMP_ERR_WRONGLENGTH:		      raw::c_long =  8;
pub const SNMP_ERR_WRONGENCODING:	      raw::c_long =  9;
pub const SNMP_ERR_WRONGVALUE:		      raw::c_long = 10;
pub const SNMP_ERR_NOCREATION:		      raw::c_long = 11;
pub const SNMP_ERR_INCONSISTENTVALUE:	  raw::c_long = 12;
pub const SNMP_ERR_RESOURCEUNAVAILABLE: raw::c_long = 13;
pub const SNMP_ERR_COMMITFAILED:        raw::c_long = 14;
pub const SNMP_ERR_UNDOFAILED:	        raw::c_long = 15;
pub const SNMP_ERR_AUTHORIZATIONERROR:  raw::c_long = 16;
pub const SNMP_ERR_NOTWRITABLE:         raw::c_long = 17;
pub const SNMP_ERR_INCONSISTENTNAME:    raw::c_long = 18;

pub const SNMPERR_SUCCESS:                      raw::c_int =   0;     /* XXX  Non-PDU "success" code. */
pub const SNMPERR_GENERR:                       raw::c_int =  -1;
pub const SNMPERR_BAD_LOCPORT:                  raw::c_int =  -2;
pub const SNMPERR_BAD_ADDRESS:                  raw::c_int =  -3;
pub const SNMPERR_BAD_SESSION:                  raw::c_int =  -4;
pub const SNMPERR_TOO_LONG:                     raw::c_int =  -5;
pub const SNMPERR_NO_SOCKET:                    raw::c_int =  -6;
pub const SNMPERR_V2_IN_V1:                     raw::c_int =  -7;
pub const SNMPERR_V1_IN_V2:                     raw::c_int =  -8;
pub const SNMPERR_BAD_REPEATERS:                raw::c_int =  -9;
pub const SNMPERR_BAD_REPETITIONS:              raw::c_int = -10;
pub const SNMPERR_BAD_ASN1_BUILD:               raw::c_int = -11;
pub const SNMPERR_BAD_SENDTO:                   raw::c_int = -12;
pub const SNMPERR_BAD_PARSE:                    raw::c_int = -13;
pub const SNMPERR_BAD_VERSION:                  raw::c_int = -14;
pub const SNMPERR_BAD_SRC_PARTY:                raw::c_int = -15;
pub const SNMPERR_BAD_DST_PARTY:                raw::c_int = -16;
pub const SNMPERR_BAD_CONTEXT:                  raw::c_int = -17;
pub const SNMPERR_BAD_COMMUNITY:                raw::c_int = -18;
pub const SNMPERR_NOAUTH_DESPRIV:               raw::c_int = -19;
pub const SNMPERR_BAD_ACL:                      raw::c_int = -20;
pub const SNMPERR_BAD_PARTY:                    raw::c_int = -21;
pub const SNMPERR_ABORT:                        raw::c_int = -22;
pub const SNMPERR_UNKNOWN_PDU:                  raw::c_int = -23;
pub const SNMPERR_TIMEOUT:                      raw::c_int = -24;
pub const SNMPERR_BAD_RECVFROM:                 raw::c_int = -25;
pub const SNMPERR_BAD_ENG_ID:                   raw::c_int = -26;
pub const SNMPERR_BAD_SEC_NAME:                 raw::c_int = -27;
pub const SNMPERR_BAD_SEC_LEVEL:                raw::c_int = -28;
pub const SNMPERR_ASN_PARSE_ERR:                raw::c_int = -29;
pub const SNMPERR_UNKNOWN_SEC_MODEL:            raw::c_int = -30;
pub const SNMPERR_INVALID_MSG:                  raw::c_int = -31;
pub const SNMPERR_UNKNOWN_ENG_ID:               raw::c_int = -32;
pub const SNMPERR_UNKNOWN_USER_NAME:            raw::c_int = -33;
pub const SNMPERR_UNSUPPORTED_SEC_LEVEL:        raw::c_int = -34;
pub const SNMPERR_AUTHENTICATION_FAILURE:       raw::c_int = -35;
pub const SNMPERR_NOT_IN_TIME_WINDOW:           raw::c_int = -36;
pub const SNMPERR_DECRYPTION_ERR:               raw::c_int = -37;
pub const SNMPERR_SC_GENERAL_FAILURE:           raw::c_int = -38;
pub const SNMPERR_SC_NOT_CONFIGURED:            raw::c_int = -39;
pub const SNMPERR_KT_NOT_AVAILABLE:             raw::c_int = -40;
pub const SNMPERR_UNKNOWN_REPORT:               raw::c_int = -41;
pub const SNMPERR_USM_GENERICERROR:             raw::c_int = -42;
pub const SNMPERR_USM_UNKNOWNSECURITYNAME:      raw::c_int = -43;
pub const SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL: raw::c_int = -44;
pub const SNMPERR_USM_ENCRYPTIONERROR:          raw::c_int = -45;
pub const SNMPERR_USM_AUTHENTICATIONFAILURE:    raw::c_int = -46;
pub const SNMPERR_USM_PARSEERROR:               raw::c_int = -47;
pub const SNMPERR_USM_UNKNOWNENGINEID:          raw::c_int = -48;
pub const SNMPERR_USM_NOTINTIMEWINDOW:          raw::c_int = -49;
pub const SNMPERR_USM_DECRYPTIONERROR:          raw::c_int = -50;
pub const SNMPERR_NOMIB:                        raw::c_int = -51;
pub const SNMPERR_RANGE:                        raw::c_int = -52;
pub const SNMPERR_MAX_SUBID:                    raw::c_int = -53;
pub const SNMPERR_BAD_SUBID:                    raw::c_int = -54;
pub const SNMPERR_LONG_OID:                     raw::c_int = -55;
pub const SNMPERR_BAD_NAME:                     raw::c_int = -56;
pub const SNMPERR_VALUE:                        raw::c_int = -57;
pub const SNMPERR_UNKNOWN_OBJID:                raw::c_int = -58;
pub const SNMPERR_NULL_PDU:                     raw::c_int = -59;
pub const SNMPERR_NO_VARS:                      raw::c_int = -60;
pub const SNMPERR_VAR_TYPE:                     raw::c_int = -61;
pub const SNMPERR_MALLOC:                       raw::c_int = -62;
pub const SNMPERR_KRB5:                         raw::c_int = -63;
pub const SNMPERR_PROTOCOL:                     raw::c_int = -64;
pub const SNMPERR_OID_NONINCREASING:            raw::c_int = -65;
pub const SNMPERR_JUST_A_CONTEXT_PROBE:         raw::c_int = -66;
pub const SNMPERR_TRANSPORT_NO_CONFIG:          raw::c_int = -67;
pub const SNMPERR_TRANSPORT_CONFIG_ERROR:       raw::c_int = -68;
pub const SNMPERR_TLS_NO_CERTIFICATE:           raw::c_int = -69;
pub const SNMPERR_MAX:                          raw::c_int = -69;

pub const ASN_BOOLEAN:	    raw::c_uchar = 0x01;
pub const ASN_INTEGER:	    raw::c_uchar = 0x02;
pub const ASN_BIT_STR:	    raw::c_uchar = 0x03;
pub const ASN_OCTET_STR:    raw::c_uchar = 0x04;
pub const ASN_NULL:	        raw::c_uchar = 0x05;
pub const ASN_OBJECT_ID:	  raw::c_uchar = 0x06;
pub const ASN_SEQUENCE:	    raw::c_uchar = 0x10;
pub const ASN_SET:		      raw::c_uchar = 0x11;
pub const ASN_UNIVERSAL:	  raw::c_uchar = 0x00;
pub const ASN_APPLICATION:  raw::c_uchar = 0x40;
pub const ASN_CONTEXT:	    raw::c_uchar = 0x80;
pub const ASN_PRIVATE:	    raw::c_uchar = 0xC0;
pub const ASN_PRIMITIVE:	  raw::c_uchar = 0x00;
pub const ASN_CONSTRUCTOR:	raw::c_uchar = 0x20;

pub const ASN_IPADDRESS:    raw::c_uchar = (ASN_APPLICATION |  0);
pub const ASN_COUNTER:      raw::c_uchar = (ASN_APPLICATION |  1);
pub const ASN_GAUGE:        raw::c_uchar = (ASN_APPLICATION |  2);
pub const ASN_UNSIGNED:     raw::c_uchar = (ASN_APPLICATION |  2); // RFC 1902 - same as GAUGE
pub const ASN_TIMETICKS:    raw::c_uchar = (ASN_APPLICATION |  3);
pub const ASN_OPAQUE:       raw::c_uchar = (ASN_APPLICATION |  4); // changed so no conflict with other includes
pub const ASN_NSAP:         raw::c_uchar = (ASN_APPLICATION |  5); // historic - don't use
pub const ASN_COUNTER64:    raw::c_uchar = (ASN_APPLICATION |  6);
pub const ASN_UINTEGER:     raw::c_uchar = (ASN_APPLICATION |  7); // historic - don't use
pub const ASN_FLOAT:        raw::c_uchar = (ASN_APPLICATION |  8);
pub const ASN_DOUBLE:       raw::c_uchar = (ASN_APPLICATION |  9);
pub const ASN_INTEGER64:    raw::c_uchar = (ASN_APPLICATION | 10);
pub const ASN_UNSIGNED64:   raw::c_uchar = (ASN_APPLICATION | 11);

pub const USM_AUTH_KU_LEN: usize = 32;
pub const USM_PRIV_KU_LEN: usize = 32;

mod auto;
pub use auto::*;

static INIT: Once = ONCE_INIT;

pub fn init(typ: &[u8]) {
    let mut type_dup = [0u8; 256];
    type_dup[..typ.len()].clone_from_slice(typ);
    unsafe {
        INIT.call_once(||{
            init_snmp(type_dup.as_ptr() as *mut raw::c_char);
            netsnmp_init_mib();
        })
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! FBX binary parser.

use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{ParserSource, BasicSource, SeekableSource, LimitedSeekReader};

mod error;
mod event;
mod reader;
pub mod utils;

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for whole FBX with binary format.
#[derive(Debug)]
pub struct RootParser<R> {
    /// Source reader.
    source: R,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Vec<Warning>,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
}

impl<R: Read> RootParser<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        RootParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

impl<R: Read + io::Seek> RootParser<SeekableSource<R>> {
    /// Creates a new binary parser.
    pub fn from_seekable(source: R) -> Self {
        RootParser {
            source: SeekableSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

impl<R: ParserSource> RootParser<R> {
    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &Vec<Warning> {
        &self.warnings
    }

    /// Parses FBX from the given stream and returns the next event.
    pub fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match self.state.clone()? {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(builder?.build(self))
    }

    /// Skip to the end of the current node.
    ///
    /// Returns `Ok(true)` if the current node is skipped and closed,
    /// `Ok(false)` if no nodes are open (i.e. the parser is reading under implicit root node),
    /// `Err(err)` if error happened.
    pub fn skip_current_node(&mut self) -> Result<bool> {
        if let Some(end) = self.open_nodes.pop().map(|v| v.end) {
            self.source.skip_to(end)?;
            self.state = Ok(State::NodeEnded);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        debug!("Parser: {:#?}", self);
        self.warnings.push(warning);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = read_fbx_header(self)?;
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        self.skip_attributes()?;

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.position() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = self.read_node_event()?;
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = NodeHeader::read_from_parser(self)?;
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.position();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.bytelen_name as usize];
            self.source.read_exact(&mut name_vec)?;
            let name = String::from_utf8(name_vec).map_err(Error::node_name_invalid_utf8)?;
            let current_pos = self.source.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder {
                name: name,
                header: header,
            }
            .into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`RootParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}
<commit_msg>Fix documentation a little<commit_after>//! FBX binary parser.

use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{ParserSource, BasicSource, SeekableSource, LimitedSeekReader};

mod error;
mod event;
mod reader;
pub mod utils;

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for whole FBX with binary format.
#[derive(Debug)]
pub struct RootParser<R> {
    /// Source reader.
    source: R,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Vec<Warning>,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
}

impl<R: Read> RootParser<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        RootParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

impl<R: Read + io::Seek> RootParser<SeekableSource<R>> {
    /// Creates a new binary parser.
    pub fn from_seekable(source: R) -> Self {
        RootParser {
            source: SeekableSource::new(source),
            state: Ok(State::Header),
            warnings: Vec::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
        }
    }
}

impl<R: ParserSource> RootParser<R> {
    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &Vec<Warning> {
        &self.warnings
    }

    /// Parses FBX from the given stream and returns the next event.
    pub fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match self.state.clone()? {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(builder?.build(self))
    }

    /// Skips to the end of the current node.
    ///
    /// Returns `Ok(true)` if the current node is skipped and closed,
    /// `Ok(false)` if no nodes are open (i.e. the parser is reading under implicit root node),
    /// `Err(err)` if error happened.
    pub fn skip_current_node(&mut self) -> Result<bool> {
        if let Some(end) = self.open_nodes.pop().map(|v| v.end) {
            self.source.skip_to(end)?;
            self.state = Ok(State::NodeEnded);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        debug!("Parser: {:#?}", self);
        self.warnings.push(warning);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = read_fbx_header(self)?;
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        self.skip_attributes()?;

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.position() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = self.read_node_event()?;
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = NodeHeader::read_from_parser(self)?;
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.position();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            let mut name_vec = vec![0u8; header.bytelen_name as usize];
            self.source.read_exact(&mut name_vec)?;
            let name = String::from_utf8(name_vec).map_err(Error::node_name_invalid_utf8)?;
            let current_pos = self.source.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder {
                name: name,
                header: header,
            }
            .into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`RootParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}
<|endoftext|>