<commit_before>// Copyright (C) 2015 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Crate dependencies
extern crate libc;
extern crate pam_sys as pam;
extern crate users;

// Modules
mod ffi;
mod simple;

// Re-Exports
pub use simple::*;

// Usings
use pam::{PamConversation, PamFlag, PamHandle, PamReturnCode};

/// Main struct to authenticate a user
pub struct Authenticator<'a> {
    handle:         *mut PamHandle,
    credentials:    Box<[&'a str; 2]>
}

impl <'a> Authenticator<'a> {
    /// Creates a new Authenticator with a given service name
    pub fn new(service: &str) -> Option<Authenticator> {
        use std::ffi::CString;
        use std::ptr;

        let creds = Box::new([""; 2]);
        let conv = PamConversation {
            conv:       Some(ffi::converse),
            data_ptr:   creds.as_ptr() as *mut ::libc::c_void
        };
        let mut handle: *mut PamHandle = ptr::null_mut();

        match unsafe {
            pam::start(CString::new(service).unwrap().as_ptr(), ptr::null(), &conv, &mut handle)
        } {
            PamReturnCode::SUCCESS => Some(Authenticator {
                handle:         handle,
                credentials:    creds
            }),
            _   => None
        }
    }

    /// Set the credentials which should be used in the authentication process
    pub fn set_credentials(&mut self, user: &'a str, password: &'a str) {
        self.credentials[0] = user;
        self.credentials[1] = password;
    }

    /// Perform the authentication with the provided credentials
    pub fn authenticate(&self) -> Result<(), PamReturnCode> {
        let success = PamReturnCode::SUCCESS;

        let mut res = unsafe { pam::authenticate(self.handle, PamFlag::NONE) };
        if res != success {
            return self.fail(res);
        }

        res = unsafe { pam::acct_mgmt(self.handle, PamFlag::NONE) };
        if res != success {
            return self.fail(res);
        }

        res = unsafe { pam::setcred(self.handle, PamFlag::ESTABLISH_CRED) };
        if res != success {
            return self.fail(res);
        }
        Ok(())
    }

    /// Open a session for a previously authenticated user and
    /// initialize the environment appropriately (in PAM and regular enviroment variables).
    ///
    /// Does not currently check for authentication and just calls the ffi method,
    /// but clients should not rely on that.
    pub fn open_session(&self) -> Result<(), PamReturnCode> {
        let res = unsafe { pam::open_session(self.handle, PamFlag::NONE) };
        if res != PamReturnCode::SUCCESS {
            return self.fail(res);
        }

        self.initialize_environment()
    }

    // Initialize the client environment with common variables.
    // Currently always called from Authenticator.open_session()
    fn initialize_environment(&self) -> Result<(), PamReturnCode> {
        let user = users::get_user_by_name(self.credentials[0])
            .expect(&format!("Could not get user by name: {:?}", self.credentials[0]));

        self.set_env("USER", &user.name)
            .and(self.set_env("LOGNAME", &user.name))
            .and(self.set_env("HOME", &user.home_dir))
            .and(self.set_env("PWD", &user.home_dir))
            .and(self.set_env("SHELL", &user.shell))
            // Taken from https://github.com/gsingh93/display-manager/blob/master/pam.c
            // Should be a better way to get this. Revisit later.
            .and(self.set_env("PATH", "$PATH:/usr/local/sbin:/usr/local/bin:/usr/bin"))
    }

    // Utility function to set an environment variable in PAM and the process
    fn set_env(&self, key: &str, value: &str) -> Result<(), PamReturnCode> {
        use std::env;
        use std::ffi::CString;

        // Set regular environment variable
        env::set_var(key, value);

        // Set pam environment variable
        let name_value = CString::new(format!("{}={}", key, value)).unwrap();
        match unsafe { pam::putenv(self.handle, name_value.as_ptr()) } {
            PamReturnCode::SUCCESS  => Ok(()),
            code                    => Err(code)
        }
    }

    // Utility function to properly clean up pam
    // TODO: Move or copy this into Authenticator.drop()?
    fn fail(&self, code: PamReturnCode) -> Result<(), PamReturnCode> {
        unsafe {
            pam::setcred(self.handle, pam::PamFlag::DELETE_CRED);
            pam::end(self.handle, 0);
        }
        Err(code)
    }
}
<commit_msg>Implemented Drop for Authenticator<commit_after>// Copyright (C) 2015 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Crate dependencies
extern crate libc;
extern crate pam_sys as pam;
extern crate users;

// Modules
mod ffi;
mod simple;

// Re-Exports
pub use simple::*;

// Usings
use pam::{PamConversation, PamFlag, PamHandle, PamReturnCode};

/// Main struct to authenticate a user
/// Currently closes the session on drop() but this might change!
pub struct Authenticator<'a> {
    handle:         *mut PamHandle,
    credentials:    Box<[&'a str; 2]>
}

impl <'a> Authenticator<'a> {
    /// Creates a new Authenticator with a given service name
    pub fn new(service: &str) -> Option<Authenticator> {
        use std::ffi::CString;
        use std::ptr;

        let creds = Box::new([""; 2]);
        let conv = PamConversation {
            conv:       Some(ffi::converse),
            data_ptr:   creds.as_ptr() as *mut ::libc::c_void
        };
        let mut handle: *mut PamHandle = ptr::null_mut();

        match unsafe {
            pam::start(CString::new(service).unwrap().as_ptr(), ptr::null(), &conv, &mut handle)
        } {
            PamReturnCode::SUCCESS => Some(Authenticator {
                handle:         handle,
                credentials:    creds
            }),
            _   => None
        }
    }

    /// Set the credentials which should be used in the authentication process
    pub fn set_credentials(&mut self, user: &'a str, password: &'a str) {
        self.credentials[0] = user;
        self.credentials[1] = password;
    }

    /// Perform the authentication with the provided credentials
    pub fn authenticate(&self) -> Result<(), PamReturnCode> {
        let success = PamReturnCode::SUCCESS;

        let mut res = unsafe { pam::authenticate(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::acct_mgmt(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::setcred(self.handle, PamFlag::ESTABLISH_CRED) };
        if res != success {
            return self.cleanup(res);
        }
        Ok(())
    }

    /// Open a session for a previously authenticated user and
    /// initialize the environment appropriately (in PAM and regular enviroment variables).
    ///
    /// Does not currently check for authentication and just calls the ffi method,
    /// but clients should not rely on that.
    pub fn open_session(&self) -> Result<(), PamReturnCode> {
        let res = unsafe { pam::open_session(self.handle, PamFlag::NONE) };
        if res != PamReturnCode::SUCCESS {
            return self.cleanup(res);
        }

        self.initialize_environment()
    }

    // Initialize the client environment with common variables.
    // Currently always called from Authenticator.open_session()
    fn initialize_environment(&self) -> Result<(), PamReturnCode> {
        let user = users::get_user_by_name(self.credentials[0])
            .expect(&format!("Could not get user by name: {:?}", self.credentials[0]));

        self.set_env("USER", &user.name)
            .and(self.set_env("LOGNAME", &user.name))
            .and(self.set_env("HOME", &user.home_dir))
            .and(self.set_env("PWD", &user.home_dir))
            .and(self.set_env("SHELL", &user.shell))
            // Taken from https://github.com/gsingh93/display-manager/blob/master/pam.c
            // Should be a better way to get this. Revisit later.
            .and(self.set_env("PATH", "$PATH:/usr/local/sbin:/usr/local/bin:/usr/bin"))
    }

    // Utility function to set an environment variable in PAM and the process
    fn set_env(&self, key: &str, value: &str) -> Result<(), PamReturnCode> {
        use std::env;
        use std::ffi::CString;

        // Set regular environment variable
        env::set_var(key, value);

        // Set pam environment variable
        let name_value = CString::new(format!("{}={}", key, value)).unwrap();
        match unsafe { pam::putenv(self.handle, name_value.as_ptr()) } {
            PamReturnCode::SUCCESS  => Ok(()),
            code                    => Err(code)
        }
    }

    // Utility function to properly clean up pam
    fn cleanup(&self, code: PamReturnCode) -> Result<(), PamReturnCode> {
        unsafe {
            // Currently the session is closed if PamReturnCode::SUCCESS is passed //TODO: change this
            if code == PamReturnCode::SUCCESS {
                pam::close_session(self.handle, PamFlag::NONE);
            }
            pam::setcred(self.handle, pam::PamFlag::DELETE_CRED);
            pam::end(self.handle, 0);
        }
        Err(code)
    }
}

impl <'a> Drop for Authenticator<'a> {
    fn drop(&mut self) {
        self.cleanup(PamReturnCode::SUCCESS);
    }
}
<|endoftext|>


<commit_before>/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
const LOREM_IPSUM: &str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
const LIBER_PRIMUS: &str = include_str!("liber-primus.txt");

/// Generate a standard lorem ipsum text.
pub fn lipsum() -> String {
    String::from(LOREM_IPSUM)
}

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

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum()[..11], "Lorem ipsum");
    }
}
<commit_msg>lib: explain how to use LIBER_PRIMUS with LOREM_IPSUM<commit_after>/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely. However, combining it with the full text in
/// [`LIBER_PRIMUS`] works well.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
/// [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
const LOREM_IPSUM: &str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
const LIBER_PRIMUS: &str = include_str!("liber-primus.txt");

/// Generate a standard lorem ipsum text.
pub fn lipsum() -> String {
    String::from(LOREM_IPSUM)
}

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

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum()[..11], "Lorem ipsum");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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.

pub mod color;
pub mod data_provider;
pub mod errors;
pub mod iterator;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use errors::{ErrorKind, Result};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }

    pub fn from_proto(attr_proto: proto::AttributeDataType) -> Result<Self> {
        let attr = match attr_proto {
            proto::AttributeDataType::U8 => AttributeDataType::U8,
            proto::AttributeDataType::I64 => AttributeDataType::I64,
            proto::AttributeDataType::U64 => AttributeDataType::U64,
            proto::AttributeDataType::F32 => AttributeDataType::F32,
            proto::AttributeDataType::F64 => AttributeDataType::F64,
            proto::AttributeDataType::U8Vec3 => AttributeDataType::U8Vec3,
            proto::AttributeDataType::F64Vec3 => AttributeDataType::F64Vec3,
            proto::AttributeDataType::U16
            | proto::AttributeDataType::U32
            | proto::AttributeDataType::I8
            | proto::AttributeDataType::I16
            | proto::AttributeDataType::I32 => {
                return Err(ErrorKind::InvalidInput(
                    "Attribute data type not supported yet".to_string(),
                )
                .into())
            }
            proto::AttributeDataType::INVALID_DATA_TYPE => {
                return Err(
                    ErrorKind::InvalidInput("Attribute data type invalid".to_string()).into(),
                )
            }
        };
        Ok(attr)
    }

    pub fn size_of(self) -> usize {
        match self {
            AttributeDataType::U8 => 1,
            AttributeDataType::F32 => 4,
            AttributeDataType::I64 | AttributeDataType::U64 | AttributeDataType::F64 => 8,
            AttributeDataType::U8Vec3 => 3,
            AttributeDataType::F64Vec3 => 3 * 8,
        }
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

macro_rules! try_from_impl {
    ($data:ident, $attribute_data_type:ident, $vec_data_type:ty) => {
        match $data {
            AttributeData::$attribute_data_type(data) => Ok(data),
            _ => Err(format!(
                "Attribute data type '{:?}' is incompatible with requested type '{}'.",
                $data.data_type(),
                stringify!($vec_data_type)
            )),
        }
    };
}

macro_rules! try_from_attribute_data {
    ($attribute_data_type:ident, $vec_data_type:ty) => {
        impl TryFrom<AttributeData> for Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a AttributeData> for &'a Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a mut AttributeData> for &'a mut Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a mut AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }
    };
}
try_from_attribute_data!(U8, u8);
try_from_attribute_data!(I64, i64);
try_from_attribute_data!(U64, u64);
try_from_attribute_data!(F32, f32);
try_from_attribute_data!(F64, f64);
try_from_attribute_data!(U8Vec3, Vector3<u8>);
try_from_attribute_data!(F64Vec3, Vector3<f64>);

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

impl PointsBatch {
    pub fn get_attribute_vec<'a, T>(
        &'a self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a Vec<T>, String>
    where
        &'a Vec<T>: TryFrom<&'a AttributeData, Error = String>,
    {
        self.attributes
            .get(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn get_attribute_vec_mut<'a, T>(
        &'a mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a mut Vec<T>, String>
    where
        &'a mut Vec<T>: TryFrom<&'a mut AttributeData, Error = String>,
    {
        self.attributes
            .get_mut(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn remove_attribute_vec<T>(
        &mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<Vec<T>, String>
    where
        Vec<T>: TryFrom<AttributeData, Error = String>,
    {
        self.attributes
            .remove(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }
}

pub use point_viewer_proto_rust::proto;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;
<commit_msg>Manipulations for points batches. (#355)<commit_after>// Copyright 2016 Google Inc.
//
// 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.

pub mod color;
pub mod data_provider;
pub mod errors;
pub mod iterator;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use errors::{ErrorKind, Result};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;

pub trait NumberOfPoints {
    fn num_points(&self) -> Option<usize>;
}

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }

    pub fn from_proto(attr_proto: proto::AttributeDataType) -> Result<Self> {
        let attr = match attr_proto {
            proto::AttributeDataType::U8 => AttributeDataType::U8,
            proto::AttributeDataType::I64 => AttributeDataType::I64,
            proto::AttributeDataType::U64 => AttributeDataType::U64,
            proto::AttributeDataType::F32 => AttributeDataType::F32,
            proto::AttributeDataType::F64 => AttributeDataType::F64,
            proto::AttributeDataType::U8Vec3 => AttributeDataType::U8Vec3,
            proto::AttributeDataType::F64Vec3 => AttributeDataType::F64Vec3,
            proto::AttributeDataType::U16
            | proto::AttributeDataType::U32
            | proto::AttributeDataType::I8
            | proto::AttributeDataType::I16
            | proto::AttributeDataType::I32 => {
                return Err(ErrorKind::InvalidInput(
                    "Attribute data type not supported yet".to_string(),
                )
                .into())
            }
            proto::AttributeDataType::INVALID_DATA_TYPE => {
                return Err(
                    ErrorKind::InvalidInput("Attribute data type invalid".to_string()).into(),
                )
            }
        };
        Ok(attr)
    }

    pub fn size_of(self) -> usize {
        match self {
            AttributeDataType::U8 => 1,
            AttributeDataType::F32 => 4,
            AttributeDataType::I64 | AttributeDataType::U64 | AttributeDataType::F64 => 8,
            AttributeDataType::U8Vec3 => 3,
            AttributeDataType::F64Vec3 => 3 * 8,
        }
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

macro_rules! try_from_impl {
    ($data:ident, $attribute_data_type:ident, $vec_data_type:ty) => {
        match $data {
            AttributeData::$attribute_data_type(data) => Ok(data),
            _ => Err(format!(
                "Attribute data type '{:?}' is incompatible with requested type '{}'.",
                $data.data_type(),
                stringify!($vec_data_type)
            )),
        }
    };
}

macro_rules! try_from_attribute_data {
    ($attribute_data_type:ident, $vec_data_type:ty) => {
        impl TryFrom<AttributeData> for Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a AttributeData> for &'a Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a mut AttributeData> for &'a mut Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a mut AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }
    };
}
try_from_attribute_data!(U8, u8);
try_from_attribute_data!(I64, i64);
try_from_attribute_data!(U64, u64);
try_from_attribute_data!(F32, f32);
try_from_attribute_data!(F64, f64);
try_from_attribute_data!(U8Vec3, Vector3<u8>);
try_from_attribute_data!(F64Vec3, Vector3<f64>);

fn append_attribute<'a, T: 'a>(
    name: &str,
    to: &'a mut PointsBatch,
    from: &'a mut PointsBatch,
) -> std::result::Result<(), String>
where
    &'a mut Vec<T>: TryFrom<&'a mut AttributeData, Error = String>,
{
    let to_vec: &'a mut Vec<T> = to.get_attribute_vec_mut(name)?;
    let from_vec: &'a mut Vec<T> = from.get_attribute_vec_mut(name)?;
    to_vec.append(from_vec);
    Ok(())
}

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

impl PointsBatch {
    pub fn append(&mut self, other: &mut PointsBatch) -> std::result::Result<(), String> {
        if self.position.is_empty() {
            *self = other.split_off(0);
        } else {
            assert_eq!(self.attributes.len(), other.attributes.len());
            self.position.append(&mut other.position);
            let data_types: Vec<(String, AttributeDataType)> = self
                .attributes
                .iter()
                .map(|(name, attrib)| (name.clone(), attrib.data_type()))
                .collect();
            for (name, dtype) in &data_types {
                use AttributeDataType::*;
                match dtype {
                    U8 => append_attribute::<u8>(name, self, other)?,
                    U64 => append_attribute::<u64>(name, self, other)?,
                    I64 => append_attribute::<i64>(name, self, other)?,
                    F32 => append_attribute::<f32>(name, self, other)?,
                    F64 => append_attribute::<f64>(name, self, other)?,
                    U8Vec3 => append_attribute::<Vector3<u8>>(name, self, other)?,
                    F64Vec3 => append_attribute::<Vector3<f64>>(name, self, other)?,
                };
            }
        }
        Ok(())
    }

    pub fn split_off(&mut self, at: usize) -> Self {
        let mut res = Self {
            position: self.position.split_off(at),
            attributes: BTreeMap::new(),
        };
        for (name, attribute) in self.attributes.iter_mut() {
            let name = name.clone();
            use AttributeData::*;
            match attribute {
                U8(data) => res.attributes.insert(name, U8(data.split_off(at))),
                U64(data) => res.attributes.insert(name, U64(data.split_off(at))),
                I64(data) => res.attributes.insert(name, I64(data.split_off(at))),
                F32(data) => res.attributes.insert(name, F32(data.split_off(at))),
                F64(data) => res.attributes.insert(name, F64(data.split_off(at))),
                U8Vec3(data) => res.attributes.insert(name, U8Vec3(data.split_off(at))),
                F64Vec3(data) => res.attributes.insert(name, F64Vec3(data.split_off(at))),
            };
        }
        res
    }

    pub fn retain(&mut self, keep: &[bool]) {
        assert_eq!(self.position.len(), keep.len());
        let mut keep = keep.iter().copied().cycle();
        self.position.retain(|_| keep.next().unwrap());
        for a in self.attributes.values_mut() {
            match a {
                AttributeData::U8(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::U64(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::I64(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::F32(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::F64(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::U8Vec3(data) => data.retain(|_| keep.next().unwrap()),
                AttributeData::F64Vec3(data) => data.retain(|_| keep.next().unwrap()),
            }
        }
    }

    pub fn get_attribute_vec<'a, T>(
        &'a self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a Vec<T>, String>
    where
        &'a Vec<T>: TryFrom<&'a AttributeData, Error = String>,
    {
        self.attributes
            .get(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn get_attribute_vec_mut<'a, T>(
        &'a mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a mut Vec<T>, String>
    where
        &'a mut Vec<T>: TryFrom<&'a mut AttributeData, Error = String>,
    {
        self.attributes
            .get_mut(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn remove_attribute_vec<T>(
        &mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<Vec<T>, String>
    where
        Vec<T>: TryFrom<AttributeData, Error = String>,
    {
        self.attributes
            .remove(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }
}

pub use point_viewer_proto_rust::proto;
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;
use syn::*;

#[macro_use]
extern crate quote;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

#[derive(Debug)]
struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {

    let ends: Vec<u8> = bitfields.iter().map(|x| match &x.position {
        &BitFieldPosition::Single(x) => x,
        &BitFieldPosition::Range(ref range) => range.end
    }).collect();

    let max_ends = ends.iter().max().unwrap();

    let base_size: usize = (*max_ends as usize / 8) + 1;

    let mut impl_body = quote! {};

    for bitfield in bitfields {
        println!("iter field {} @{:?}", bitfield.ident, bitfield.position);

        let getter_str = format!("get_{}", bitfield.ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", bitfield.ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        let ty = &bitfield.ty;

        match &bitfield.position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << (x % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = x as usize / 8;

                let shift = x % 8;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: [u8;1] = [(self.0[#byteidx] & #mask) >> #shift];
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: [u8;1] = std::convert::Into::into(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw[0] & 1) << #shift;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from = range.start;
                let to = range.end;

                let value_size: usize = (to - from) as usize / 8 + 1;
                // let value_bit_size = to - from + 1;

                let from_byte: usize = from as usize / 8;
                let to_byte: usize = to as usize / 8;

                let raw_size = to_byte - from_byte + 1;

                println!("value_byte_size:{}", value_size);
                println!("from_byte:{}, to_byte:{}", from_byte, to_byte);
                println!("raw_size:{}", raw_size);

                // let type_mask: u8 = (1 << type_bit_size) - 1;
                // let mask: u8 = type_mask << (from % 8);
                // let nmask: u8 = !mask;

                let bit_shift = from % 8;
                let bit_end = to % 8;

                let mut setter_body = quote! {
                    let value_array: [u8;#value_size] = std::convert::Into::into(value);
                    let mut raw: u8;
                };

                for i in 0..raw_size {

                    if i < value_size {
                        if bit_shift == 0 {
                            setter_body = quote! { #setter_body
                                 raw = value_array[#i];
                            }
                        } else {
                            setter_body = quote! { #setter_body
                                raw = value_array[#i] << #bit_shift;
                            }
                        }
                    } else {
                        setter_body = quote! { #setter_body
                            raw = 0;
                        }
                    }

                    if i != 0 {
                        let i_1 = i - 1;
                        if bit_shift != 0 {
                            setter_body = quote! { #setter_body
                                raw |= value_array[#i_1] >> (8 - #bit_shift);
                            }
                        }
                    }

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    let i_from_byte = i + from_byte;

                    if mask != 0xff {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] &= !#mask;
                            self.0[#i_from_byte] |= raw & #mask;
                        };
                    } else {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] = raw;
                        };
                    }
                }

                let mut getter_body = quote! {
                    let mut value_array: [u8;#value_size] = [0;#value_size];
                };

                for i in 0..value_size {

                    let i_from_byte = i + from_byte;

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    getter_body = quote! { #getter_body
                        value_array[#i] = self.0[#i_from_byte] >> #bit_shift;
                    };

                    if i < raw_size - 1 {
                        let i_from_byte = i + from_byte + 1;
                        if bit_shift != 0 {
                            getter_body = quote! { #getter_body
                                value_array[#i] |= self.0[#i_from_byte] << (8 - #bit_shift);
                            }
                        }
                    }

                    if mask != 0xff {
                        getter_body = quote! { #getter_body
                            value_array[#i] &= #mask;
                        };
                    }
                }

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        #getter_body
                        return std::convert::From::from(value_array);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        #setter_body
                    }
                }
            },
        }
    };

    return quote! {
        struct #name ([u8;#base_size]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0;#base_size]);
            }
        }
        impl #name {

            #impl_body
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    #[derive(Debug)]
    let mut bitfields: Vec<BitField> = vec![];

    for field in &fields {
        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        let ident = field.ident.clone().unwrap();

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return output_struct(name, &bitfields).parse().unwrap();
}<commit_msg>add pub struct<commit_after>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;
use syn::*;

#[macro_use]
extern crate quote;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

#[derive(Debug)]
struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {

    let ends: Vec<u8> = bitfields.iter().map(|x| match &x.position {
        &BitFieldPosition::Single(x) => x,
        &BitFieldPosition::Range(ref range) => range.end
    }).collect();

    let max_ends = ends.iter().max().unwrap();

    let base_size: usize = (*max_ends as usize / 8) + 1;

    let mut impl_body = quote! {};

    for bitfield in bitfields {
        println!("iter field {} @{:?}", bitfield.ident, bitfield.position);

        let getter_str = format!("get_{}", bitfield.ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", bitfield.ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        let ty = &bitfield.ty;

        match &bitfield.position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << (x % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = x as usize / 8;

                let shift = x % 8;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: [u8;1] = [(self.0[#byteidx] & #mask) >> #shift];
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: [u8;1] = std::convert::Into::into(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw[0] & 1) << #shift;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from = range.start;
                let to = range.end;

                let value_size: usize = (to - from) as usize / 8 + 1;
                // let value_bit_size = to - from + 1;

                let from_byte: usize = from as usize / 8;
                let to_byte: usize = to as usize / 8;

                let raw_size = to_byte - from_byte + 1;

                println!("value_byte_size:{}", value_size);
                println!("from_byte:{}, to_byte:{}", from_byte, to_byte);
                println!("raw_size:{}", raw_size);

                // let type_mask: u8 = (1 << type_bit_size) - 1;
                // let mask: u8 = type_mask << (from % 8);
                // let nmask: u8 = !mask;

                let bit_shift = from % 8;
                let bit_end = to % 8;

                let mut setter_body = quote! {
                    let value_array: [u8;#value_size] = std::convert::Into::into(value);
                    let mut raw: u8;
                };

                for i in 0..raw_size {

                    if i < value_size {
                        if bit_shift == 0 {
                            setter_body = quote! { #setter_body
                                 raw = value_array[#i];
                            }
                        } else {
                            setter_body = quote! { #setter_body
                                raw = value_array[#i] << #bit_shift;
                            }
                        }
                    } else {
                        setter_body = quote! { #setter_body
                            raw = 0;
                        }
                    }

                    if i != 0 {
                        let i_1 = i - 1;
                        if bit_shift != 0 {
                            setter_body = quote! { #setter_body
                                raw |= value_array[#i_1] >> (8 - #bit_shift);
                            }
                        }
                    }

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    let i_from_byte = i + from_byte;

                    if mask != 0xff {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] &= !#mask;
                            self.0[#i_from_byte] |= raw & #mask;
                        };
                    } else {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] = raw;
                        };
                    }
                }

                let mut getter_body = quote! {
                    let mut value_array: [u8;#value_size] = [0;#value_size];
                };

                for i in 0..value_size {

                    let i_from_byte = i + from_byte;

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    getter_body = quote! { #getter_body
                        value_array[#i] = self.0[#i_from_byte] >> #bit_shift;
                    };

                    if i < raw_size - 1 {
                        let i_from_byte = i + from_byte + 1;
                        if bit_shift != 0 {
                            getter_body = quote! { #getter_body
                                value_array[#i] |= self.0[#i_from_byte] << (8 - #bit_shift);
                            }
                        }
                    }

                    if mask != 0xff {
                        getter_body = quote! { #getter_body
                            value_array[#i] &= #mask;
                        };
                    }
                }

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        #getter_body
                        return std::convert::From::from(value_array);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        #setter_body
                    }
                }
            },
        }
    };

    return quote! {
        pub struct #name ([u8;#base_size]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0;#base_size]);
            }
        }
        impl #name {

            #impl_body
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    #[derive(Debug)]
    let mut bitfields: Vec<BitField> = vec![];

    for field in &fields {
        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        let ident = field.ident.clone().unwrap();

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return output_struct(name, &bitfields).parse().unwrap();
}<|endoftext|>


<commit_before>
//! Hubcaps provides a set of building blocks for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

use rustc_serialize::{json, Decodable};
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;

pub use rep::*;
pub use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, ContentLength, UserAgent};
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories};
use std::fmt;
use std::io::Read;

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
#[derive(Debug, PartialEq)]
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Debug, PartialEq)]
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: String,
    agent: String,
    client: &'a Client,
    token: Option<String>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new<A,T>(
        agent: A,
        client: &'a Client,
        token: Option<T>
    ) -> Github<'a> where A : Into<String>, T: Into<String> {
        Github::host(DEFAULT_HOST, agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H,A,T>(
        host: H,
        agent: A,
        client: &'a Client,
        token: Option<T>
     ) -> Github<'a> where H: Into<String>, A: Into<String>, T: Into<String>{
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            token: token.map(|t| t.into())
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O,R>(&self, owner: O, repo: R) -> Repository where O: Into<String>, R: Into<String> {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by an
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories where S: Into<String>{
        UserRepositories::new(self, owner)
    }

    /// Return a reference to  the collection of repositores owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists where O: Into<String> {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request<D>(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<D> where D : Decodable {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(ref token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = try!(
            match body {
                Some(ref bod) => authenticated.body(*bod).send(),
                _ => authenticated.send()
            }
        );
        let mut body =
            match res.headers.clone().get::<ContentLength>() {
                Some(&ContentLength(len)) =>
                    String::with_capacity(len as usize),
                _ => String::new()
            };
        try!(res.read_to_string(&mut body));
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault {
                    code: res.status,
                    error: try!(json::decode::<ClientError>(&body))
                }
            ),
            _ =>
                Ok(try!(json::decode::<D>(&body)))
        }
    }

    fn get<D>(&self, uri: &str) -> Result<D> where D: Decodable {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request::<()>(
            Method::Delete,
            uri,
            None
        ) {
            Err(Error::Decoding(_)) => Ok(()),
            otherwise => otherwise
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }
}
<commit_msg>state and sortdir should be cloneable<commit_after>
//! Hubcaps provides a set of building blocks for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

use rustc_serialize::{json, Decodable};
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;

pub use rep::*;
pub use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, ContentLength, UserAgent};
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories};
use std::fmt;
use std::io::Read;

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Clone, Debug, PartialEq)]
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: String,
    agent: String,
    client: &'a Client,
    token: Option<String>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new<A,T>(
        agent: A,
        client: &'a Client,
        token: Option<T>
    ) -> Github<'a> where A : Into<String>, T: Into<String> {
        Github::host(DEFAULT_HOST, agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H,A,T>(
        host: H,
        agent: A,
        client: &'a Client,
        token: Option<T>
     ) -> Github<'a> where H: Into<String>, A: Into<String>, T: Into<String>{
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            token: token.map(|t| t.into())
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O,R>(&self, owner: O, repo: R) -> Repository where O: Into<String>, R: Into<String> {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by an
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories where S: Into<String>{
        UserRepositories::new(self, owner)
    }

    /// Return a reference to  the collection of repositores owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists where O: Into<String> {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request<D>(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<D> where D : Decodable {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(ref token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = try!(
            match body {
                Some(ref bod) => authenticated.body(*bod).send(),
                _ => authenticated.send()
            }
        );
        let mut body =
            match res.headers.clone().get::<ContentLength>() {
                Some(&ContentLength(len)) =>
                    String::with_capacity(len as usize),
                _ => String::new()
            };
        try!(res.read_to_string(&mut body));
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault {
                    code: res.status,
                    error: try!(json::decode::<ClientError>(&body))
                }
            ),
            _ =>
                Ok(try!(json::decode::<D>(&body)))
        }
    }

    fn get<D>(&self, uri: &str) -> Result<D> where D: Decodable {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request::<()>(
            Method::Delete,
            uri,
            None
        ) {
            Err(Error::Decoding(_)) => Ok(()),
            otherwise => otherwise
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D> where D: Decodable {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }
}
<|endoftext|>


<commit_before>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::intrinsics::unreachable.
#![feature(core)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable fixed-topology view of a tree.
///
/// This trait defines a view of a tree that is analogous to a sequential
/// iterator providing read-only pointers into a structure. At any given point
/// in time, it can be thought of as pointing to a particular tree node. Methods
/// are provided for walking the tree and updating which node is pointed at. A
/// guarded reference to the data at a node can be obtained at any time, with
/// the lifetime of the reference good for the lifetime of the view of the tree.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should provide an
/// implementation of `std::borrow::Borrow` or `std::borrow::BorrowMut`.
///
/// The read-only nature of this view does not guarantee immutability or thread
/// safety. Trees with an internall internally mutable node type (like
/// `std::cell::RefCell<T>`) may permit updates to tree data through this
/// view. The tree topology, however, should stay fixed.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone`.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. An offset of 0 is a no-op. Panics if this is the tree root or
    /// `offset` resolves to a nonexistant sibling.
    fn seek_sibling(&mut self, offset: isize);

    /// Navigates to the child at at the given index. Panics if there are no
    /// children to navigate to or `index` resolves to a nonexistant child.
    fn seek_child(&mut self, index: usize);

    /// Navigates to this node's parent. Panics if this is the root.
    fn to_parent(&mut self);

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

pub trait Editor: Nav {
    type Data;
    type Tree;

    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    fn push_child(&mut self, child: <Self as Editor>::Tree);

    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data);

    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree);

    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data);

    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree);

    fn remove(&mut self) -> <Self as Editor>::Tree;

    fn remove_child(&mut self, index: usize) -> <Self as Editor>::Tree;

    fn remove_sibling(&mut self, offset: isize) -> <Self as Editor>::Tree;

    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    fn swap_children(&mut self, index_a: usize, index_b: usize);

    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize);
}

// #[macro_export]
// macro_rules! tree {
//     ($data:expr) => ($crate::Tree::leaf($data));
//     ($data:expr, [$($first:tt)*] $(,[$($rest:tt)*])*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
//     ($data:expr, ($($first:tt)*) $(,($($rest:tt)*))*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
//     ($data:expr, {$($first:tt)*} $(,{$($rest:tt)*})*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
// }

// impl<'a, T: Debug + 'a, G: Guard<'a, T>> Debug for Nav<'a, Data=T, DataGuard=G> {
//     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//         enum Walk<T> { Down(T), Up, };
//         let mut stack = Vec::new();
//         try![write!(f, "({:?}", self.data().deref())];
//         stack.push(Walk::Up);
//         for c in self.children.iter().rev() {
//             stack.push(Walk::Down(c));
//         }
//         loop {
//             match stack.pop() {
//                 None => return Ok(()),
//                 Some(Walk::Up) => try![write!(f, ")")],
//                 Some(Walk::Down(t)) => {
//                     try![write!(f, " ({:?}", *t.data().deref())];
//                     stack.push(Walk::Up);
//                     for c in t.children.iter().rev() {
//                         stack.push(Walk::Down(c));
//                     }
//                 },
//             }
//         }
//     }
// }

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<commit_msg>Update docs some.<commit_after>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::intrinsics::unreachable.
#![feature(core)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable fixed-topology view of a tree.
///
/// This trait defines a view of a tree that is analogous to a sequential
/// iterator providing read-only pointers into a structure. At any given point
/// in time, it can be thought of as pointing to a particular tree node. Methods
/// are provided for walking the tree and updating which node is pointed at.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should provide an
/// implementation of `std::borrow::Borrow` or `std::borrow::BorrowMut`.
///
/// The read-only nature of this view does not guarantee immutability or thread
/// safety. Trees with an internall internally mutable node type (like
/// `std::cell::RefCell<T>`) may permit updates to tree data through this
/// view. The tree topology, however, should stay fixed.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone`.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. An offset of 0 is a no-op. Panics if this is the tree root or
    /// `offset` resolves to a nonexistant sibling.
    fn seek_sibling(&mut self, offset: isize);

    /// Navigates to the child at at the given index. Panics if there are no
    /// children to navigate to or `index` resolves to a nonexistant child.
    fn seek_child(&mut self, index: usize);

    /// Navigates to this node's parent. Panics if this is the root.
    fn to_parent(&mut self);

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

pub trait Editor: Nav {
    type Data;
    type Tree;

    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    fn push_child(&mut self, child: <Self as Editor>::Tree);

    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data);

    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree);

    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data);

    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree);

    fn remove(&mut self) -> <Self as Editor>::Tree;

    fn remove_child(&mut self, index: usize) -> <Self as Editor>::Tree;

    fn remove_sibling(&mut self, offset: isize) -> <Self as Editor>::Tree;

    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    fn swap_children(&mut self, index_a: usize, index_b: usize);

    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize);
}

// #[macro_export]
// macro_rules! tree {
//     ($data:expr) => ($crate::Tree::leaf($data));
//     ($data:expr, [$($first:tt)*] $(,[$($rest:tt)*])*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
//     ($data:expr, ($($first:tt)*) $(,($($rest:tt)*))*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
//     ($data:expr, {$($first:tt)*} $(,{$($rest:tt)*})*) =>
//         ($crate::Tree { data: $data,
//                         children: vec![tree![$($first)*]
//                                        $(,tree![$($rest)*])*] });
// }

// impl<'a, T: Debug + 'a, G: Guard<'a, T>> Debug for Nav<'a, Data=T, DataGuard=G> {
//     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//         enum Walk<T> { Down(T), Up, };
//         let mut stack = Vec::new();
//         try![write!(f, "({:?}", self.data().deref())];
//         stack.push(Walk::Up);
//         for c in self.children.iter().rev() {
//             stack.push(Walk::Down(c));
//         }
//         loop {
//             match stack.pop() {
//                 None => return Ok(()),
//                 Some(Walk::Up) => try![write!(f, ")")],
//                 Some(Walk::Down(t)) => {
//                     try![write!(f, " ({:?}", *t.data().deref())];
//                     stack.push(Walk::Up);
//                     for c in t.children.iter().rev() {
//                         stack.push(Walk::Down(c));
//                     }
//                 },
//             }
//         }
//     }
// }

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<|endoftext|>