<commit_before>extern crate libc;

use libc::{c_void};
use std::ffi::CStr;
use std::ffi::CString;
use std::{fmt, process, ptr};
use std::collections::HashMap;
use std::mem;
use std::mem::{transmute};
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};

use std::sync::{Arc, Mutex};

use super::super::couchbase::*;

use super::super::couchbase::types::response::format_error;

// Gets
pub type OperationResultGet = Result<response::Get, (Option<response::Get>, &'static str)>;
pub type OperationResultGetCallback = Box<Box<Fn(&response::Get)>>;
pub type OperationResultGetInternal<'a> = Result<&'a response::GetInternal, (Option<&'a response::GetInternal>, &'static str)>;
pub type OperationResultGetInternalCallback = Box<Box<Fn(&response::GetInternal)>>;

// Stores
pub type OperationResultStore = Result<response::Store, (Option<response::Store>, &'static str)>;
pub type OperationResultStoreCallback = Box<Box<Fn(&response::Store)>>;
pub type OperationResultStoreInternal<'a> = Result<&'a response::StoreInternal, (Option<&'a response::StoreInternal>, &'static str)>;
pub type OperationResultStoreInternalCallback = Box<Box<Fn(&response::StoreInternal)>>;

pub struct CouchbaseOperation<T> {
    counter: u64,
    map: HashMap<u64, T>
}

impl<T> fmt::Debug for CouchbaseOperation<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CouchbaseOperation {{ counter: {}, length: {} }}", self.counter, self.map.len())
    }
}

impl<T> CouchbaseOperation<T> {
    pub fn new() -> CouchbaseOperation<T> {
        CouchbaseOperation {
            counter: 0,
            map: HashMap::new()
        }
    }

    pub fn increment_counter(&mut self) -> u64 {
        self.counter += 1;
        return self.counter;
    }
}

#[derive(Debug)]
pub struct CouchbaseOperations {
    get: CouchbaseOperation<cmd::Get>,
    store: CouchbaseOperation<cmd::Get>,
}

impl CouchbaseOperations {
    pub fn new() -> CouchbaseOperations {
        CouchbaseOperations {
            get: CouchbaseOperation::new(),
            store: CouchbaseOperation::new()
        }
    }
}

#[derive(Debug)]
pub struct Client {
    pub opts: Arc<Mutex<CreateSt>>,
    pub instance: Instance,
    pub uri: String,
    pub operations: CouchbaseOperations
}

impl Client {
    /// Constructor
    pub fn new(uri: &str) -> Client {
        let connstr = CString::new(uri).unwrap();

        let mut opts = CreateSt::default();
        opts.v3.connstr = connstr.as_ptr();

        let mut instance: Instance = ptr::null_mut();

        unsafe {
            let res = lcb_create(&mut instance as *mut Instance, &opts as *const CreateSt);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            info!("Connecting to {}", uri);

            let res = lcb_connect(instance);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            let res = lcb_wait(instance);
            if res != ErrorType::Success {
                error!("lcb_wait() failed - {:?}", res);
            }

            let res = lcb_get_bootstrap_status(instance);
            if res != ErrorType::Success {
                error!("lcb_get_bootstrap_status() failed - {:?}, \"{}\"",
                         res,
                         CStr::from_ptr(lcb_strerror(instance, res)).to_str().unwrap()
                );
                process::exit(-1);
            }

            lcb_install_callback3(instance, CallbackType::Get, Some(op_callback));
            lcb_install_callback3(instance, CallbackType::Store, Some(op_callback));

            Client {
                opts: Arc::new(Mutex::new(opts)),
                instance: instance,
                uri: uri.to_string(),
                operations: CouchbaseOperations::new()

            }
        }
    }

    ///  Will cause the operation to fail if the key already exists in the cluster.
    pub fn add<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Add, callback);
    }

    /// Rather than setting the contents of the entire document, take the value specified in value and _append_ it to the existing bytes in the value.
    pub fn append<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Append, callback);
    }

    /// Get document from database
    pub fn get<'a, F>(&'a mut self, key: &str, callback: F) -> &Client
        where F: Fn(OperationResultGet) + 'static
    {
        let mut gcmd = cmd::Get::default();

        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = key.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;

        unsafe {
            let _id = self.operations.get.increment_counter();

            let boxed: OperationResultGetInternalCallback = Box::new(Box::new(move |result: &response::GetInternal| {
                match result.rc {
                    ErrorType::Success => {
                        debug!("{:?}", result);
                        callback(Ok(response::Get::new(result)));
                    },
                    _ => {
                        callback(Err((Some(response::Get::new(result)), "error" /* result.error(self.instance) */)));
                    }
                }
            }));

            debug!("Boxed box occupies {} bytes in the stack", mem::size_of_val(&boxed));

            // let user_data = transmute::<*const _, *mut c_void>(Box::into_raw(boxed));
            let user_data = Box::into_raw(boxed) as *mut Box<Fn(&response::GetInternal)> as *mut c_void;
            debug!("Setting get callback address {:?}", user_data);

            let res = lcb_get3(self.instance, user_data, &gcmd as *const cmd::Get);
            if res != ErrorType::Success {
                // callback(Err((None, format_error(self.instance, &res))));
            } else {
                let res = lcb_wait(self.instance);
                if res != ErrorType::Success {
                    // callback(Err((None, format_error(self.instance, &res))))
                }
            }
        }

        return self;
    }

    pub fn get_sync(&mut self, key: &str) -> OperationResultGet
    {
        let (tx, rx): (Sender<OperationResultGet>, Receiver<OperationResultGet>) = mpsc::channel();
        self.get(key, move |result: OperationResultGet| {
            let _ = tx.send(result);
        });
        return rx.recv().unwrap();
    }

    /// Like append, but prepends the new value to the existing value.
    pub fn prepend<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Prepend, callback);
    }

    /// Will cause the operation to fail _unless_ the key already exists in the cluster.
    pub fn replace<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Replace, callback);
    }

    /// Unconditionally store the item in the cluster
    pub fn set<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Set, callback);
    }

    /// Store document in database
    pub fn store<'a, F>(&'a mut self, key: &str, value: &str, operation: Operation, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        let mut gcmd = cmd::Store::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = key.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;
        gcmd.value._type = KvBufferType::Copy;
        gcmd.value.contig.bytes = value.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.value.contig.nbytes = value.len() as u64;
        gcmd.operation = operation;

        unsafe {
            let _id = self.operations.store.increment_counter();

            let boxed: OperationResultStoreInternalCallback = Box::new(Box::new(move |result: &response::StoreInternal| {
                match result.rc {
                    ErrorType::Success => {
                        debug!("{:?}", result);
                        callback(Ok(response::Store::new(result)));
                    },
                    _ => {
                        callback(Err((Some(response::Store::new(result)), "error" /* result.error(self.instance) */)));
                    }
                }
            }));

            debug!("Boxed box occupies {} bytes in the stack", mem::size_of_val(&boxed));

            // let user_data = transmute::<*const  _, *mut c_void>(Box::into_raw(boxed));
            let user_data = Box::into_raw(boxed) as *mut Box<Fn(&response::StoreInternal)> as *mut c_void;
            debug!("Setting store callback address {:?}", user_data);

            let res = lcb_store3(self.instance, user_data, &gcmd as *const cmd::Store);
            if res != ErrorType::Success {
                // callback(Err((None, format_error(self.instance, &res))))
            } else {
                let res = lcb_wait(self.instance);
                if res != ErrorType::Success {
                    // callback(Err((None, format_error(self.instance, &res))))
                }
            }
        }

        return self;
    }

    /// Behaviorally it is identical to set in that it will make the server unconditionally store the item, whether it exists or not.
    pub fn upsert<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Upsert, callback);
    }
}

impl Drop for Client {
    fn drop(&mut self) {
        unsafe {
            info!("Disconnecting from {}", self.uri);
            lcb_destroy(self.instance);
        }
    }
}

/// libcouchbse callback
unsafe extern "C" fn op_callback(_instance: Instance, cbtype: CallbackType, resp: *const response::Base) {
    match cbtype {
        CallbackType::Get => {
            let gresp = resp as *const response::GetInternal;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            // let callback = transmute::<*mut c_void, *const Box<Fn(&response::GetInternal)>>(cookie);

            let callback = cookie as *const Box<Fn(&response::GetInternal)>;
            // let callback: Box<Box<Fn(&response::GetInternal)>> = Box::from_raw(cookie as *mut Box<Fn(&response::GetInternal)>);
            debug!("Retreived boxed box occupies {} bytes in the stack", mem::size_of_val(&callback));

            // debug!("Got get callback address {:?}", callback);

            (*callback)(&(*gresp));
        },
        CallbackType::Store => {
            let gresp = resp as *const response::StoreInternal;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            // let callback = transmute::<*mut c_void, *const Box<Fn(&response::StoreInternal)>>(cookie);

            let callback = cookie as *const Box<Fn(&response::StoreInternal)>;
            // let callback: Box<Box<Fn(&response::StoreInternal)>> = Box::from_raw(cookie as *mut Box<Fn(&response::StoreInternal)>);
            debug!("Retreived boxed box occupies {} bytes in the stack", mem::size_of_val(&callback));

            // debug!("Got store callback address {:?}", callback);

            (*callback)(&(*gresp));
        },
        _ => error!("! Unknown Callback...")
    };
}
<commit_msg>Show received callback<commit_after>extern crate libc;

use libc::{c_void};
use std::ffi::CStr;
use std::ffi::CString;
use std::{fmt, process, ptr};
use std::collections::HashMap;
use std::mem;
use std::mem::{transmute};
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};

use std::sync::{Arc, Mutex};

use super::super::couchbase::*;

use super::super::couchbase::types::response::format_error;

// Gets
pub type OperationResultGet = Result<response::Get, (Option<response::Get>, &'static str)>;
pub type OperationResultGetCallback = Box<Box<Fn(&response::Get)>>;
pub type OperationResultGetInternal<'a> = Result<&'a response::GetInternal, (Option<&'a response::GetInternal>, &'static str)>;
pub type OperationResultGetInternalCallback = Box<Box<Fn(&response::GetInternal)>>;

// Stores
pub type OperationResultStore = Result<response::Store, (Option<response::Store>, &'static str)>;
pub type OperationResultStoreCallback = Box<Box<Fn(&response::Store)>>;
pub type OperationResultStoreInternal<'a> = Result<&'a response::StoreInternal, (Option<&'a response::StoreInternal>, &'static str)>;
pub type OperationResultStoreInternalCallback = Box<Box<Fn(&response::StoreInternal)>>;

pub struct CouchbaseOperation<T> {
    counter: u64,
    map: HashMap<u64, T>
}

impl<T> fmt::Debug for CouchbaseOperation<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CouchbaseOperation {{ counter: {}, length: {} }}", self.counter, self.map.len())
    }
}

impl<T> CouchbaseOperation<T> {
    pub fn new() -> CouchbaseOperation<T> {
        CouchbaseOperation {
            counter: 0,
            map: HashMap::new()
        }
    }

    pub fn increment_counter(&mut self) -> u64 {
        self.counter += 1;
        return self.counter;
    }
}

#[derive(Debug)]
pub struct CouchbaseOperations {
    get: CouchbaseOperation<cmd::Get>,
    store: CouchbaseOperation<cmd::Get>,
}

impl CouchbaseOperations {
    pub fn new() -> CouchbaseOperations {
        CouchbaseOperations {
            get: CouchbaseOperation::new(),
            store: CouchbaseOperation::new()
        }
    }
}

#[derive(Debug)]
pub struct Client {
    pub opts: Arc<Mutex<CreateSt>>,
    pub instance: Instance,
    pub uri: String,
    pub operations: CouchbaseOperations
}

impl Client {
    /// Constructor
    pub fn new(uri: &str) -> Client {
        let connstr = CString::new(uri).unwrap();

        let mut opts = CreateSt::default();
        opts.v3.connstr = connstr.as_ptr();

        let mut instance: Instance = ptr::null_mut();

        unsafe {
            let res = lcb_create(&mut instance as *mut Instance, &opts as *const CreateSt);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            info!("Connecting to {}", uri);

            let res = lcb_connect(instance);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            let res = lcb_wait(instance);
            if res != ErrorType::Success {
                error!("lcb_wait() failed - {:?}", res);
            }

            let res = lcb_get_bootstrap_status(instance);
            if res != ErrorType::Success {
                error!("lcb_get_bootstrap_status() failed - {:?}, \"{}\"",
                         res,
                         CStr::from_ptr(lcb_strerror(instance, res)).to_str().unwrap()
                );
                process::exit(-1);
            }

            lcb_install_callback3(instance, CallbackType::Get, Some(op_callback));
            lcb_install_callback3(instance, CallbackType::Store, Some(op_callback));

            Client {
                opts: Arc::new(Mutex::new(opts)),
                instance: instance,
                uri: uri.to_string(),
                operations: CouchbaseOperations::new()

            }
        }
    }

    ///  Will cause the operation to fail if the key already exists in the cluster.
    pub fn add<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Add, callback);
    }

    /// Rather than setting the contents of the entire document, take the value specified in value and _append_ it to the existing bytes in the value.
    pub fn append<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Append, callback);
    }

    /// Get document from database
    pub fn get<'a, F>(&'a mut self, key: &str, callback: F) -> &Client
        where F: Fn(OperationResultGet) + 'static
    {
        let mut gcmd = cmd::Get::default();

        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = key.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;

        unsafe {
            let _id = self.operations.get.increment_counter();

            let boxed: OperationResultGetInternalCallback = Box::new(Box::new(move |result: &response::GetInternal| {
                match result.rc {
                    ErrorType::Success => {
                        debug!("{:?}", result);
                        callback(Ok(response::Get::new(result)));
                    },
                    _ => {
                        callback(Err((Some(response::Get::new(result)), "error" /* result.error(self.instance) */)));
                    }
                }
            }));

            debug!("Boxed box occupies {} bytes in the stack", mem::size_of_val(&boxed));

            // let user_data = transmute::<*const _, *mut c_void>(Box::into_raw(boxed));
            let user_data = Box::into_raw(boxed) as *mut Box<Fn(&response::GetInternal)> as *mut c_void;
            debug!("Setting get callback address {:?}", user_data);

            let res = lcb_get3(self.instance, user_data, &gcmd as *const cmd::Get);
            if res != ErrorType::Success {
                // callback(Err((None, format_error(self.instance, &res))));
            } else {
                let res = lcb_wait(self.instance);
                if res != ErrorType::Success {
                    // callback(Err((None, format_error(self.instance, &res))))
                }
            }
        }

        return self;
    }

    pub fn get_sync(&mut self, key: &str) -> OperationResultGet
    {
        let (tx, rx): (Sender<OperationResultGet>, Receiver<OperationResultGet>) = mpsc::channel();
        self.get(key, move |result: OperationResultGet| {
            let _ = tx.send(result);
        });
        return rx.recv().unwrap();
    }

    /// Like append, but prepends the new value to the existing value.
    pub fn prepend<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Prepend, callback);
    }

    /// Will cause the operation to fail _unless_ the key already exists in the cluster.
    pub fn replace<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Replace, callback);
    }

    /// Unconditionally store the item in the cluster
    pub fn set<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Set, callback);
    }

    /// Store document in database
    pub fn store<'a, F>(&'a mut self, key: &str, value: &str, operation: Operation, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        let mut gcmd = cmd::Store::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = key.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;
        gcmd.value._type = KvBufferType::Copy;
        gcmd.value.contig.bytes = value.as_bytes().as_ptr() as *const libc::c_void;
        gcmd.value.contig.nbytes = value.len() as u64;
        gcmd.operation = operation;

        unsafe {
            let _id = self.operations.store.increment_counter();

            let boxed: OperationResultStoreInternalCallback = Box::new(Box::new(move |result: &response::StoreInternal| {
                match result.rc {
                    ErrorType::Success => {
                        debug!("{:?}", result);
                        callback(Ok(response::Store::new(result)));
                    },
                    _ => {
                        callback(Err((Some(response::Store::new(result)), "error" /* result.error(self.instance) */)));
                    }
                }
            }));

            debug!("Boxed box occupies {} bytes in the stack", mem::size_of_val(&boxed));

            // let user_data = transmute::<*const  _, *mut c_void>(Box::into_raw(boxed));
            let user_data = Box::into_raw(boxed) as *mut Box<Fn(&response::StoreInternal)> as *mut c_void;
            debug!("Setting store callback address {:?}", user_data);

            let res = lcb_store3(self.instance, user_data, &gcmd as *const cmd::Store);
            if res != ErrorType::Success {
                // callback(Err((None, format_error(self.instance, &res))))
            } else {
                let res = lcb_wait(self.instance);
                if res != ErrorType::Success {
                    // callback(Err((None, format_error(self.instance, &res))))
                }
            }
        }

        return self;
    }

    /// Behaviorally it is identical to set in that it will make the server unconditionally store the item, whether it exists or not.
    pub fn upsert<'a, F>(&'a mut self, key: &str, value: &str, callback: F) -> &Client
        where F: Fn(OperationResultStore) + 'static
    {
        return self.store(key, value, Operation::Upsert, callback);
    }
}

impl Drop for Client {
    fn drop(&mut self) {
        unsafe {
            info!("Disconnecting from {}", self.uri);
            lcb_destroy(self.instance);
        }
    }
}

/// libcouchbse callback
unsafe extern "C" fn op_callback(_instance: Instance, cbtype: CallbackType, resp: *const response::Base) {
    match cbtype {
        CallbackType::Get => {
            let gresp = resp as *const response::GetInternal;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            // let callback = transmute::<*mut c_void, *const Box<Fn(&response::GetInternal)>>(cookie);

            let callback = cookie as *const Box<Fn(&response::GetInternal)>;
            // let callback: Box<Box<Fn(&response::GetInternal)>> = Box::from_raw(cookie as *mut Box<Fn(&response::GetInternal)>);
            debug!("Retreived boxed box occupies {} bytes in the stack", mem::size_of_val(&callback));

            debug!("Got get callback address {:?}", callback);

            (*callback)(&(*gresp));
        },
        CallbackType::Store => {
            let gresp = resp as *const response::StoreInternal;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            // let callback = transmute::<*mut c_void, *const Box<Fn(&response::StoreInternal)>>(cookie);

            let callback = cookie as *const Box<Fn(&response::StoreInternal)>;
            // let callback: Box<Box<Fn(&response::StoreInternal)>> = Box::from_raw(cookie as *mut Box<Fn(&response::StoreInternal)>);
            debug!("Retreived boxed box occupies {} bytes in the stack", mem::size_of_val(&callback));

            debug!("Got store callback address {:?}", callback);

            (*callback)(&(*gresp));
        },
        _ => error!("! Unknown Callback...")
    };
}
<|endoftext|>


<commit_before>// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use peek_poke::{PeekPoke, Poke};
use std::{marker::PhantomData, mem::size_of};

#[test]
fn test_numbers() {
    assert_eq!(u8::max_size(), size_of::<u8>());
    assert_eq!(u16::max_size(), size_of::<u16>());
    assert_eq!(u32::max_size(), size_of::<u32>());
    assert_eq!(u64::max_size(), size_of::<u64>());
    assert_eq!(usize::max_size(), size_of::<usize>());
    assert_eq!(i8::max_size(), size_of::<i8>());
    assert_eq!(i16::max_size(), size_of::<i16>());
    assert_eq!(i32::max_size(), size_of::<i32>());
    assert_eq!(i64::max_size(), size_of::<i64>());
    assert_eq!(isize::max_size(), size_of::<isize>());
    // floating
    assert_eq!(f32::max_size(), size_of::<f32>());
    assert_eq!(f64::max_size(), size_of::<f64>());
}

#[test]
fn test_bool() {
    assert_eq!(bool::max_size(), size_of::<u8>());
}

#[test]
fn test_option() {
    assert_eq!(
        Option::<usize>::max_size(),
        <u8>::max_size() + <usize>::max_size()
    );
}

#[test]
fn test_fixed_size_array() {
    assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::<u32>());
    assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::<u64>());
    assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::<u8>());
}

#[test]
fn test_tuple() {
    assert_eq!(<(isize)>::max_size(), size_of::<isize>());
    assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::<isize>());
    assert_eq!(<(isize, ())>::max_size(), size_of::<isize>());
}

#[test]
fn test_basic_struct() {
    #[derive(Debug, PeekPoke)]
    struct Bar {
        a: u32,
        b: u32,
        c: u32,
    }

    assert_eq!(<Bar>::max_size(), 3 * <u32>::max_size());
}

#[test]
fn test_enum() {
    #[derive(Clone, Copy, PeekPoke)]
    enum TestEnum {
        NoArg,
        OneArg(usize),
        Args(usize, usize),
        AnotherNoArg,
        StructLike { x: usize, y: f32 },
    }
    assert_eq!(
        TestEnum::max_size(),
        <u8>::max_size() + 2 * <usize>::max_size()
    );
}

#[test]
fn test_enum_cstyle() {
    #[repr(u32)]
    #[derive(Clone, Copy, PeekPoke)]
    enum BorderStyle {
        None = 0,
        Solid = 1,
        Double = 2,
        Dotted = 3,
        Dashed = 4,
        Hidden = 5,
        Groove = 6,
        Ridge = 7,
        Inset = 8,
        Outset = 9,
    }
    assert_eq!(BorderStyle::max_size(), <u8>::max_size());
}

#[test]
fn test_phantom_data() {
    struct Bar;
    #[derive(PeekPoke)]
    struct Foo {
        x: u32,
        y: u32,
        _marker: PhantomData<Bar>,
    }
    assert_eq!(Foo::max_size(), 2 * size_of::<u32>())
}
<commit_msg>Bug 1612988 - Fix warning in a peek_poke test. r=jrmuizel<commit_after>// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use peek_poke::{PeekPoke, Poke};
use std::{marker::PhantomData, mem::size_of};

#[test]
fn test_numbers() {
    assert_eq!(u8::max_size(), size_of::<u8>());
    assert_eq!(u16::max_size(), size_of::<u16>());
    assert_eq!(u32::max_size(), size_of::<u32>());
    assert_eq!(u64::max_size(), size_of::<u64>());
    assert_eq!(usize::max_size(), size_of::<usize>());
    assert_eq!(i8::max_size(), size_of::<i8>());
    assert_eq!(i16::max_size(), size_of::<i16>());
    assert_eq!(i32::max_size(), size_of::<i32>());
    assert_eq!(i64::max_size(), size_of::<i64>());
    assert_eq!(isize::max_size(), size_of::<isize>());
    // floating
    assert_eq!(f32::max_size(), size_of::<f32>());
    assert_eq!(f64::max_size(), size_of::<f64>());
}

#[test]
fn test_bool() {
    assert_eq!(bool::max_size(), size_of::<u8>());
}

#[test]
fn test_option() {
    assert_eq!(
        Option::<usize>::max_size(),
        <u8>::max_size() + <usize>::max_size()
    );
}

#[test]
fn test_fixed_size_array() {
    assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::<u32>());
    assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::<u64>());
    assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::<u8>());
}

#[test]
fn test_tuple() {
    assert_eq!(<(isize, )>::max_size(), size_of::<isize>());
    assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::<isize>());
    assert_eq!(<(isize, ())>::max_size(), size_of::<isize>());
}

#[test]
fn test_basic_struct() {
    #[derive(Debug, PeekPoke)]
    struct Bar {
        a: u32,
        b: u32,
        c: u32,
    }

    assert_eq!(<Bar>::max_size(), 3 * <u32>::max_size());
}

#[test]
fn test_enum() {
    #[derive(Clone, Copy, PeekPoke)]
    enum TestEnum {
        NoArg,
        OneArg(usize),
        Args(usize, usize),
        AnotherNoArg,
        StructLike { x: usize, y: f32 },
    }
    assert_eq!(
        TestEnum::max_size(),
        <u8>::max_size() + 2 * <usize>::max_size()
    );
}

#[test]
fn test_enum_cstyle() {
    #[repr(u32)]
    #[derive(Clone, Copy, PeekPoke)]
    enum BorderStyle {
        None = 0,
        Solid = 1,
        Double = 2,
        Dotted = 3,
        Dashed = 4,
        Hidden = 5,
        Groove = 6,
        Ridge = 7,
        Inset = 8,
        Outset = 9,
    }
    assert_eq!(BorderStyle::max_size(), <u8>::max_size());
}

#[test]
fn test_phantom_data() {
    struct Bar;
    #[derive(PeekPoke)]
    struct Foo {
        x: u32,
        y: u32,
        _marker: PhantomData<Bar>,
    }
    assert_eq!(Foo::max_size(), 2 * size_of::<u32>())
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate futures;
extern crate futures_cpupool;

use std::vec::Vec;

use weld;
use slog;
use hyper::{Get, Post,Put,Delete, StatusCode};
use hyper::server::{Service, Request, Response};
use hyper;
use futures::Stream;
use futures::Future;

pub struct RestService {
    pub logger: slog::Logger,
    pub thread_pool: futures_cpupool::CpuPool,

}

impl RestService {
    /// Prepares an error response , logs it, wraps to BoxFuture.
    pub fn error(
                 response: Response,
                 code: StatusCode,
                 message: &str)
                 -> Result<Response,hyper::Error>{
        // error!(self.logger, "{}",&message);
        return Ok(response.with_status(code).with_body(message.to_string()));
    }

    /// Prepares an success response, wraps to BoxFuture.
    pub fn success(
                   response: Response,
                   value: &serde_json::Value)
                   -> Result<Response,hyper::Error> {
        return Ok(response.with_body(serde_json::to_vec(&value).unwrap()));
    }

    pub fn read_body(req: Request)-> Vec<u8>{
        req.body().fold(Vec::<u8>::new(), |mut v, chunk| {
                                v.extend(&chunk[..]);
                                futures::future::ok::<_, hyper::Error>(v)
        }).wait().unwrap()
    }
}

impl Service for RestService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        self.thread_pool.spawn_fn(move || {
            let path: &String = &req.path().into();
            let parts = path.split("/").filter(|x| !x.is_empty()).collect::<Vec<_>>().clone();
            let mut db = weld::DATABASE.lock().unwrap();
            let response = Response::new();
            // response.with_header("Content-Type", "application/json");
            match parts.len() {
                // Table list
                0 => return RestService::success(response,&serde_json::to_value(&db.tables()).unwrap()),
                1 | 2 => {
                    // Record list or record
                    let table = parts.get(0).unwrap();
                    let mut id = -1;
                    match parts.get(1) {
                        Some(val) => {
                            if !val.is_empty() {
                                match i64::from_str_radix(val, 10) {
                                    Ok(parsed) => id = parsed,
                                    Err(e) => {
                                        return RestService::error(response,
                                                        StatusCode::PreconditionFailed,
                                                        &format!("Non parsable id Error: {}", e))
                                    }

                                }
                            }
                        }
                        None => {}
                    }
                    match req.method(){
                        &Get=>{
                            match db.read(table, &id) {
                                Some(record) => return RestService::success(response, &record),
                                None => return RestService::error(response, StatusCode::NotFound, "Record not found"),
                            }
                        }
                        &Post=>{
                            let mut payload: serde_json::Value = serde_json::from_slice(Self::read_body(req).as_slice()).unwrap();
                            match db.insert(table,payload.as_object_mut().unwrap()) {
                                Some(record) => {db.flush(); return RestService::success(response, &record)}
                                None => return RestService::error(response, StatusCode::NotFound, "Record not found"),
                            }
                        }
                        &Put=>{
                            let  payload: serde_json::Value = serde_json::from_slice(Self::read_body(req).as_slice()).unwrap();
                            match db.update(table,payload.as_object().unwrap().clone()) {
                                Some(record) => {db.flush(); return RestService::success(response, &record)}
                                None => return RestService::error(response, StatusCode::NotFound, "Record not found"),
                            }
                        }
                        &Delete=>{
                            match db.delete(table,&id) {
                                Some(record) => {db.flush();return RestService::success(response, &record)}
                                None => return RestService::error(response, StatusCode::NotFound, "Record not found"),
                            }
                        }
                        _ =>{
                            RestService::error(response, StatusCode::MethodNotAllowed, "Method Not Allowed")
                        }
                    }
                }
                _ => {
                    return RestService::error(response, StatusCode::InternalServerError, "Nested structures are not implemented yet.");
                }
            }}).boxed()
        }
    }

<commit_msg>REFACTOR: Cleaning code structure<commit_after>extern crate serde_json;
extern crate futures;
extern crate futures_cpupool;

use std::vec::Vec;
use std::io;

use weld;
use slog;
use hyper::{Get, Post, Put, Delete, StatusCode};
use hyper::server::{Service, Request, Response};
use hyper;
use futures::Stream;
use futures::Future;
use futures::future::ok;

pub struct RestService {
    pub logger: slog::Logger,
    pub thread_pool: futures_cpupool::CpuPool,
}

impl RestService {
    /// Prepares an error response , logs it, wraps to BoxFuture.
    pub fn error(response: Response,
                 code: StatusCode,
                 message: &str)
                 -> futures::BoxFuture<Response, hyper::Error> {
        // error!(self.logger, "{}",&message);
        return ok(response.with_status(code).with_body(message.to_string())).boxed();
    }

    /// Prepares an success response, wraps to BoxFuture.
    pub fn success(response: Response,
                   value: &serde_json::Value)
                   -> futures::BoxFuture<Response, hyper::Error> {
        return ok(response.with_body(serde_json::to_vec(&value).unwrap())).boxed();
    }

    /// Splits '/'  and filters empty strings
    fn split_path(path: String) -> Vec<String> {
        path.split("/").filter(|x| !x.is_empty()).map(String::from).collect::<Vec<String>>()
    }

    /// Helps to decide id value.
    fn decide_id(part: Option<&String>) -> Result<i64, String> {
        match part {
            Some(val) => {
                if !val.is_empty() {
                    match i64::from_str_radix(val, 10) {
                        Ok(parsed) => Ok(parsed),
                        Err(e) => return Err(format!("Non parsable id Error: {}", e)),
                    }
                } else {
                    Ok(-1)
                }
            }
            None => Ok(-1),
        }
    }

    #[inline]
    /// Gets records or spesific record from db and returns as a result.
    fn get(table: String,
           id: i64,
           response: Response)
           -> futures::BoxFuture<Response, hyper::Error> {
        let mut db = weld::DATABASE.lock().unwrap();
        match db.read(table.as_str(), &id) {
            Some(record) => return Self::success(response, &record),
            None => return Self::error(response, StatusCode::NotFound, "Record not found"),
        }
    }

    #[inline]
    /// Creates the record. Returns the persisted version.
    fn post(req: Request,
            table: String,
            response: Response)
            -> futures::BoxFuture<Response, hyper::Error> {
        req.body()
            .concat()
            .and_then(move |body| {
                let mut db = weld::DATABASE.lock().unwrap();
                let mut payload: serde_json::Value =
                    serde_json::from_slice(body.to_vec().as_slice()).unwrap();
                match db.insert(table.as_str(), payload.as_object_mut().unwrap()) {
                    Some(record) => {
                        db.flush();
                        return Self::success(response, &record);
                    }
                    None => return Self::error(response, StatusCode::NotFound, "Record not found"),
                }
            })
            .boxed()
    }

    #[inline]
    /// Updates the record. Returns the persisted version.
    fn put(req: Request,
           table: String,
           id: i64,
           response: Response)
           -> futures::BoxFuture<Response, hyper::Error> {
        // TODO:: use path id when updating
        req.body()
            .concat()
            .and_then(move |body| {
                let mut db = weld::DATABASE.lock().unwrap();
                let mut payload: serde_json::Value =
                    serde_json::from_slice(body.to_vec().as_slice()).unwrap();
                match db.update(table.as_str(), payload.as_object().unwrap().clone()) {
                    Some(record) => {
                        db.flush();
                        return Self::success(response, &record);
                    }
                    None => return Self::error(response, StatusCode::NotFound, "Record not found"),
                }
            })
            .boxed()
    }

    #[inline]
    /// Deletes the record. Returns the data back.
    fn delete(table: String,
              id: i64,
              response: Response)
              -> futures::BoxFuture<Response, hyper::Error> {
        let mut db = weld::DATABASE.lock().unwrap();
        match db.delete(table.as_str(), &id) {
            Some(record) => {
                db.flush();
                return Self::success(response, &record);
            }
            None => return Self::error(response, StatusCode::NotFound, "Record not found"),
        }
    }
}

impl Service for RestService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let parts = Self::split_path(req.path().to_string());
        let response = Response::new();
        // TODO: response.with_header("Content-Type", "application/json");
        match parts.len() {
            // Table list
            0 => {
                let db = weld::DATABASE.lock().unwrap();
                Self::success(response, &serde_json::to_value(&db.tables()).unwrap())
            }
            1 | 2 => {
                // Record list or record
                let table = parts.get(0).unwrap().clone();
                let id = match Self::decide_id(parts.get(1)) {
                    Ok(result) => result,
                    Err(e) => {
                        return Self::error(response, StatusCode::PreconditionFailed, e.as_str());
                    }
                };

                match req.method() {
                    &Get => Self::get(table, id, response),
                    &Post => Self::post(req, table, response),
                    &Put => Self::put(req, table, id, response),
                    &Delete => Self::delete(table, id, response),
                    _ => Self::error(response, StatusCode::MethodNotAllowed, "Method Not Allowed"),
                }
            }
            _ => {
                return Self::error(response,
                                   StatusCode::InternalServerError,
                                   "Nested structures are not implemented yet.");
            }
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::sync::Arc;
use std::collections::VecDeque;

use rope::Rope;
use node::{Node, MAX_BYTES, MAX_CHILDREN};
use str_utils::{is_grapheme_boundary, prev_grapheme_boundary, next_grapheme_boundary,
                nearest_internal_grapheme_boundary};
use child_array::ChildArray;
use small_string::SmallString;

/// An incremental `Rope` builder.
///
/// To use this builder, repeatedly call `append()` to build the rope
/// up, and call `finish()` when you're done to get the completed `Rope`.
///
/// This API is both more limited and faster than repeatedly calling
/// `Rope::insert()`, and is intended primarily for loading
/// already-existing text data from another source.
///
/// If you want to read data in from a utf8-formatted text file, see
/// `Rope::from_reader()`, which uses this builder internally.
#[derive(Debug, Clone)]
pub struct RopeBuilder {
    stack: VecDeque<Node>,
    buffer: String,
}

impl RopeBuilder {
    /// Creates a new RopeBuilder, ready for input.
    pub fn new() -> RopeBuilder {
        RopeBuilder {
            stack: {
                let mut stack = VecDeque::with_capacity(8);
                stack.push_back(Node::new());
                stack
            },
            buffer: String::with_capacity(MAX_BYTES),
        }
    }

    /// Appends `text` to the end of the in-progress `Rope`.
    ///
    /// This method is intended to be called repeatedly to incrementally
    /// build up a `Rope`.  The passed text can be as large or small as
    /// desired, but larger chunks are more efficient.
    pub fn append(&mut self, text: &str) {
        let mut text = text;

        // Repeatedly chop text off the end of the input, creating
        // leaf nodes out of them and appending them to the tree.
        while text.len() > 0 {
            // Get the text for the next leaf
            let (leaf_text, remainder) = self.get_next_leaf_text(text);
            text = remainder;

            // Append the leaf to the rope
            match leaf_text {
                NextText::None => break,
                NextText::UseBuffer => {
                    let string = SmallString::from_str(&self.buffer);
                    self.append_leaf_node(Node::Leaf(string));
                    self.buffer.clear();
                }
                NextText::String(s) => {
                    self.append_leaf_node(Node::Leaf(SmallString::from_str(s)));
                }
            }
        }
    }

    /// Finishes the build, and returns the `Rope`.
    ///
    /// Note: this consumes the builder.  If you want to continue building
    /// other ropes with the same prefix, you can clone the builder before
    /// calling `finish()`.
    pub fn finish(mut self) -> Rope {
        // Append the last leaf
        if self.buffer.len() > 0 {
            let string = SmallString::from_str(&self.buffer);
            self.append_leaf_node(Node::Leaf(string));
        }

        // Zip up all the remaining nodes on the stack
        let mut stack_idx = self.stack.len() - 1;
        while stack_idx >= 1 {
            let node = self.stack.pop_back().unwrap();
            if let Node::Internal(ref mut children) = self.stack[stack_idx - 1] {
                children.push((node.text_info(), Arc::new(node)));
            } else {
                unreachable!();
            }
            stack_idx -= 1;
        }

        // Use the root as the root for a rope, and return it.
        Rope { root: Arc::new(self.stack.pop_back().unwrap()) }
    }

    //-----------------------------------------------------------------

    // Returns (next_leaf_text, remaining_text)
    fn get_next_leaf_text<'a>(&mut self, text: &'a str) -> (NextText<'a>, &'a str) {
        if self.buffer.len() == 0 {
            if text.len() > MAX_BYTES {
                // Simplest case: just chop off the end of `text`
                let split_idx = find_good_split_idx(text, MAX_BYTES);
                if split_idx == 0 || split_idx == text.len() {
                    self.buffer.push_str(text);
                    return (NextText::None, "");
                } else {
                    return (NextText::String(&text[..split_idx]), &text[split_idx..]);
                }
            } else {
                self.buffer.push_str(text);
                return (NextText::None, "");
            }
        } else if (text.len() + self.buffer.len()) > MAX_BYTES {
            let split_idx = if self.buffer.len() < MAX_BYTES {
                nearest_internal_grapheme_boundary(text, MAX_BYTES - self.buffer.len())
            } else {
                nearest_internal_grapheme_boundary(text, 0)
            };

            if split_idx == 0 || split_idx == text.len() {
                self.buffer.push_str(text);
                return (NextText::None, "");
            } else {
                self.buffer.push_str(&text[..split_idx]);
                return (NextText::UseBuffer, &text[split_idx..]);
            }
        } else {
            self.buffer.push_str(text);
            return (NextText::None, "");
        }
    }

    fn append_leaf_node(&mut self, leaf: Node) {
        let last = self.stack.pop_back().unwrap();
        match last {
            Node::Leaf(_) => {
                if last.leaf_text().len() == 0 {
                    self.stack.push_back(leaf);
                } else {
                    let mut children = ChildArray::new();
                    children.push((last.text_info(), Arc::new(last)));
                    children.push((leaf.text_info(), Arc::new(leaf)));
                    self.stack.push_back(Node::Internal(children));
                }
            }

            Node::Internal(_) => {
                self.stack.push_back(last);
                let mut left = leaf;
                let mut stack_idx = (self.stack.len() - 1) as isize;
                loop {
                    if stack_idx < 0 {
                        // We're above the root, so do a root split.
                        let mut children = ChildArray::new();
                        children.push((left.text_info(), Arc::new(left)));
                        self.stack.push_front(Node::Internal(children));
                        break;
                    } else if self.stack[stack_idx as usize].child_count() < (MAX_CHILDREN - 1) {
                        // There's room to add a child, so do that.
                        self.stack[stack_idx as usize].children().push((
                            left.text_info(),
                            Arc::new(left),
                        ));
                        break;
                    } else {
                        // Not enough room to fit a child, so split.
                        left =
                            Node::Internal(self.stack[stack_idx as usize].children().push_split((
                                left.text_info(),
                                Arc::new(left),
                            )));
                        std::mem::swap(&mut left, &mut self.stack[stack_idx as usize]);
                        stack_idx -= 1;
                    }
                }
            }
        }
    }
}

enum NextText<'a> {
    None,
    UseBuffer,
    String(&'a str),
}

fn find_good_split_idx(text: &str, idx: usize) -> usize {
    if is_grapheme_boundary(text, idx) {
        idx
    } else {
        let prev = prev_grapheme_boundary(text, idx);
        let next = next_grapheme_boundary(text, idx);
        if prev > 0 { prev } else { next }
    }
}
<commit_msg>Fixed bug in RopeBuilder where the last child could be too small.<commit_after>use std;
use std::sync::Arc;
use std::collections::VecDeque;

use rope::Rope;
use node::{Node, MAX_BYTES, MAX_CHILDREN};
use str_utils::{is_grapheme_boundary, prev_grapheme_boundary, next_grapheme_boundary,
                nearest_internal_grapheme_boundary};
use child_array::ChildArray;
use small_string::SmallString;

/// An incremental `Rope` builder.
///
/// To use this builder, repeatedly call `append()` to build the rope
/// up, and call `finish()` when you're done to get the completed `Rope`.
///
/// This API is both more limited and faster than repeatedly calling
/// `Rope::insert()`, and is intended primarily for loading
/// already-existing text data from another source.
///
/// If you want to read data in from a utf8-formatted text file, see
/// `Rope::from_reader()`, which uses this builder internally.
#[derive(Debug, Clone)]
pub struct RopeBuilder {
    stack: VecDeque<Node>,
    buffer: String,
}

impl RopeBuilder {
    /// Creates a new RopeBuilder, ready for input.
    pub fn new() -> RopeBuilder {
        RopeBuilder {
            stack: {
                let mut stack = VecDeque::with_capacity(8);
                stack.push_back(Node::new());
                stack
            },
            buffer: String::with_capacity(MAX_BYTES),
        }
    }

    /// Appends `text` to the end of the in-progress `Rope`.
    ///
    /// This method is intended to be called repeatedly to incrementally
    /// build up a `Rope`.  The passed text can be as large or small as
    /// desired, but larger chunks are more efficient.
    pub fn append(&mut self, text: &str) {
        let mut text = text;

        // Repeatedly chop text off the end of the input, creating
        // leaf nodes out of them and appending them to the tree.
        while text.len() > 0 {
            // Get the text for the next leaf
            let (leaf_text, remainder) = self.get_next_leaf_text(text);
            text = remainder;

            // Append the leaf to the rope
            match leaf_text {
                NextText::None => break,
                NextText::UseBuffer => {
                    let string = SmallString::from_str(&self.buffer);
                    self.append_leaf_node(Node::Leaf(string));
                    self.buffer.clear();
                }
                NextText::String(s) => {
                    self.append_leaf_node(Node::Leaf(SmallString::from_str(s)));
                }
            }
        }
    }

    /// Finishes the build, and returns the `Rope`.
    ///
    /// Note: this consumes the builder.  If you want to continue building
    /// other ropes with the same prefix, you can clone the builder before
    /// calling `finish()`.
    pub fn finish(mut self) -> Rope {
        // Append the last leaf
        if self.buffer.len() > 0 {
            let string = SmallString::from_str(&self.buffer);
            self.append_leaf_node(Node::Leaf(string));
        }

        // Zip up all the remaining nodes on the stack
        let mut stack_idx = self.stack.len() - 1;
        while stack_idx >= 1 {
            let node = self.stack.pop_back().unwrap();
            if let Node::Internal(ref mut children) = self.stack[stack_idx - 1] {
                children.push((node.text_info(), Arc::new(node)));
            } else {
                unreachable!();
            }
            stack_idx -= 1;
        }

        // Get root and fix any right-side nodes with too few children.
        let mut root = self.stack.pop_back().unwrap();
        root.zip_right();

        // Use the root as the root for a rope, and return it.
        Rope { root: Arc::new(root) }
    }

    //-----------------------------------------------------------------

    // Returns (next_leaf_text, remaining_text)
    fn get_next_leaf_text<'a>(&mut self, text: &'a str) -> (NextText<'a>, &'a str) {
        if self.buffer.len() == 0 {
            if text.len() > MAX_BYTES {
                // Simplest case: just chop off the end of `text`
                let split_idx = find_good_split_idx(text, MAX_BYTES);
                if split_idx == 0 || split_idx == text.len() {
                    self.buffer.push_str(text);
                    return (NextText::None, "");
                } else {
                    return (NextText::String(&text[..split_idx]), &text[split_idx..]);
                }
            } else {
                self.buffer.push_str(text);
                return (NextText::None, "");
            }
        } else if (text.len() + self.buffer.len()) > MAX_BYTES {
            let split_idx = if self.buffer.len() < MAX_BYTES {
                nearest_internal_grapheme_boundary(text, MAX_BYTES - self.buffer.len())
            } else {
                nearest_internal_grapheme_boundary(text, 0)
            };

            if split_idx == 0 || split_idx == text.len() {
                self.buffer.push_str(text);
                return (NextText::None, "");
            } else {
                self.buffer.push_str(&text[..split_idx]);
                return (NextText::UseBuffer, &text[split_idx..]);
            }
        } else {
            self.buffer.push_str(text);
            return (NextText::None, "");
        }
    }

    fn append_leaf_node(&mut self, leaf: Node) {
        let last = self.stack.pop_back().unwrap();
        match last {
            Node::Leaf(_) => {
                if last.leaf_text().len() == 0 {
                    self.stack.push_back(leaf);
                } else {
                    let mut children = ChildArray::new();
                    children.push((last.text_info(), Arc::new(last)));
                    children.push((leaf.text_info(), Arc::new(leaf)));
                    self.stack.push_back(Node::Internal(children));
                }
            }

            Node::Internal(_) => {
                self.stack.push_back(last);
                let mut left = leaf;
                let mut stack_idx = (self.stack.len() - 1) as isize;
                loop {
                    if stack_idx < 0 {
                        // We're above the root, so do a root split.
                        let mut children = ChildArray::new();
                        children.push((left.text_info(), Arc::new(left)));
                        self.stack.push_front(Node::Internal(children));
                        break;
                    } else if self.stack[stack_idx as usize].child_count() < (MAX_CHILDREN - 1) {
                        // There's room to add a child, so do that.
                        self.stack[stack_idx as usize].children().push((
                            left.text_info(),
                            Arc::new(left),
                        ));
                        break;
                    } else {
                        // Not enough room to fit a child, so split.
                        left =
                            Node::Internal(self.stack[stack_idx as usize].children().push_split((
                                left.text_info(),
                                Arc::new(left),
                            )));
                        std::mem::swap(&mut left, &mut self.stack[stack_idx as usize]);
                        stack_idx -= 1;
                    }
                }
            }
        }
    }
}

enum NextText<'a> {
    None,
    UseBuffer,
    String(&'a str),
}

fn find_good_split_idx(text: &str, idx: usize) -> usize {
    if is_grapheme_boundary(text, idx) {
        idx
    } else {
        let prev = prev_grapheme_boundary(text, idx);
        let next = next_grapheme_boundary(text, idx);
        if prev > 0 { prev } else { next }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use lber::structure::{StructureTag, PL};
use lber::structures::{ASNTag, Boolean, OctetString, Sequence, Tag};
use lber::universal::Types;

use lazy_static::lazy_static;

pub mod types {
    //! Control type enum and variant names.
    //!
    //! Variants are individually reexported from the private submodule
    //! to inhibit exhaustive matching.
    pub use self::inner::_ControlType::{PagedResults, PostReadResp, PreReadResp};

    /// Recognized control types. Variants can't be named in the namespace
    /// of this type; they must be used through module-level reexports.
    pub type ControlType = self::inner::_ControlType;
    mod inner {
        #[derive(Clone, Copy, Debug)]
        pub enum _ControlType {
            PagedResults,
            PostReadResp,
            PreReadResp,
            #[doc(hidden)]
            _Nonexhaustive,
        }
    }
}
use self::types::ControlType;

mod assertion;
pub use self::assertion::Assertion;

mod paged_results;
pub use self::paged_results::PagedResults;

mod proxy_auth;
pub use self::proxy_auth::ProxyAuth;

mod read_entry;
pub use self::read_entry::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};

mod relax_rules;
pub use self::relax_rules::RelaxRules;

lazy_static! {
    static ref CONTROLS: HashMap<&'static str, ControlType> = {
        let mut map = HashMap::new();
        map.insert(self::paged_results::PAGED_RESULTS_OID, types::PagedResults);
        map.insert(self::read_entry::POST_READ_OID, types::PostReadResp);
        map.insert(self::read_entry::PRE_READ_OID, types::PreReadResp);
        map
    };
}

pub trait IntoRawControlVec {
    fn into(self) -> Vec<RawControl>;
}

impl IntoRawControlVec for RawControl {
    fn into(self) -> Vec<RawControl> {
        vec![self]
    }
}

impl IntoRawControlVec for Vec<RawControl> {
    fn into(self) -> Vec<RawControl> {
        self
    }
}

/// Mark a control as critical.
///
/// Most controls provided by this library implement this trait. All controls
/// are instantiated as non-critical by default, unless dictated otherwise by
/// their specification.
pub trait MakeCritical {
    /// Mark the control instance as critical. This operation consumes the control,
    /// and is irreversible.
    fn critical(self) -> CriticalControl<Self>
    where
        Self: Sized,
    {
        CriticalControl { control: self }
    }
}

/// Wrapper for a control marked as critical.
///
/// The wrapper ensures that the criticality of the control will be set to
/// true when the control is encoded.
pub struct CriticalControl<T> {
    control: T,
}

impl<T> From<CriticalControl<T>> for RawControl
where
    T: Into<RawControl>,
{
    fn from(cc: CriticalControl<T>) -> RawControl {
        let mut rc = cc.control.into();
        rc.crit = true;
        rc
    }
}

/// Conversion trait for response controls.
pub trait ControlParser {
    /// Convert the raw BER value into a control-specific struct.
    fn parse(val: &[u8]) -> Self;
}

/// Response control.
///
/// If the OID is recognized as corresponding to one of controls implemented by this
/// library while parsing raw BER data of the response, the first element will have
/// a value, otherwise it will be `None`.
#[derive(Clone, Debug)]
pub struct Control(pub Option<ControlType>, pub RawControl);

/// Generic control.
///
/// This struct can be used both for request and response controls. For requests, an
/// independently implemented control can produce an instance of this type and use it
/// to provide an element of the vector passed to
/// [`with_controls()`](../struct.LdapConn.html#method.with_controls) by calling
/// `into()` on the instance.
///
/// For responses, an instance is packed into a [`Control`](struct.Control.html) and
/// can be parsed by calling type-qualified [`parse()`](#method.parse) on that instance,
/// if a [`ControlParser`](trait.ControlParser.html) implementation exists for the
/// specified type.
#[derive(Clone, Debug)]
pub struct RawControl {
    /// OID of the control.
    pub ctype: String,
    /// Criticality, has no meaning on response.
    pub crit: bool,
    /// Raw value of the control, if any.
    pub val: Option<Vec<u8>>,
}

impl RawControl {
    /// Parse the generic control into a control-specific struct.
    ///
    /// The parser will panic if the control value is `None`.
    /// __Note__: no control known to the author signals the lack of return value by
    /// omitting the control value, so this shouldn't be a problem in practice.
    /// Nevertheless, it should be possible to report this along with other parsing errors,
    /// which is a planned future improvement.
    pub fn parse<T: ControlParser>(&self) -> T {
        T::parse(self.val.as_ref().expect("value"))
    }
}

pub fn build_tag(rc: RawControl) -> StructureTag {
    let mut seq = vec![Tag::OctetString(OctetString {
        inner: Vec::from(rc.ctype.as_bytes()),
        ..Default::default()
    })];
    if rc.crit {
        seq.push(Tag::Boolean(Boolean {
            inner: true,
            ..Default::default()
        }));
    }
    if let Some(val) = rc.val {
        seq.push(Tag::OctetString(OctetString {
            inner: val,
            ..Default::default()
        }));
    }
    Tag::Sequence(Sequence {
        inner: seq,
        ..Default::default()
    })
    .into_structure()
}

pub fn parse_controls(t: StructureTag) -> Vec<Control> {
    let tags = t.expect_constructed().expect("result sequence").into_iter();
    let mut ctrls = Vec::new();
    for ctrl in tags {
        let mut components = ctrl.expect_constructed().expect("components").into_iter();
        let ctype = String::from_utf8(
            components
                .next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("control type");
        let next = components.next();
        let (crit, maybe_val) = match next {
            None => (false, None),
            Some(c) => match c {
                StructureTag {
                    id, ref payload, ..
                } if id == Types::Boolean as u64 => match *payload {
                    PL::P(ref v) => (v[0] != 0, components.next()),
                    PL::C(_) => panic!("decoding error"),
                },
                StructureTag { id, .. } if id == Types::OctetString as u64 => {
                    (false, Some(c.clone()))
                }
                _ => panic!("decoding error"),
            },
        };
        let val = match maybe_val {
            None => None,
            Some(v) => Some(Vec::from(v.expect_primitive().expect("octet string"))),
        };
        let known_type = match CONTROLS.get(&*ctype) {
            Some(val) => Some(*val),
            None => None,
        };
        ctrls.push(Control(
            known_type,
            RawControl {
                ctype: ctype,
                crit: crit,
                val: val,
            },
        ));
    }
    ctrls
}
<commit_msg>Improve control conversions<commit_after>use std::collections::HashMap;

use lber::structure::{StructureTag, PL};
use lber::structures::{ASNTag, Boolean, OctetString, Sequence, Tag};
use lber::universal::Types;

use lazy_static::lazy_static;

pub mod types {
    //! Control type enum and variant names.
    //!
    //! Variants are individually reexported from the private submodule
    //! to inhibit exhaustive matching.
    pub use self::inner::_ControlType::{PagedResults, PostReadResp, PreReadResp};

    /// Recognized control types. Variants can't be named in the namespace
    /// of this type; they must be used through module-level reexports.
    pub type ControlType = self::inner::_ControlType;
    mod inner {
        #[derive(Clone, Copy, Debug)]
        pub enum _ControlType {
            PagedResults,
            PostReadResp,
            PreReadResp,
            #[doc(hidden)]
            _Nonexhaustive,
        }
    }
}
use self::types::ControlType;

mod assertion;
pub use self::assertion::Assertion;

mod paged_results;
pub use self::paged_results::PagedResults;

mod proxy_auth;
pub use self::proxy_auth::ProxyAuth;

mod read_entry;
pub use self::read_entry::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};

mod relax_rules;
pub use self::relax_rules::RelaxRules;

lazy_static! {
    static ref CONTROLS: HashMap<&'static str, ControlType> = {
        let mut map = HashMap::new();
        map.insert(self::paged_results::PAGED_RESULTS_OID, types::PagedResults);
        map.insert(self::read_entry::POST_READ_OID, types::PostReadResp);
        map.insert(self::read_entry::PRE_READ_OID, types::PreReadResp);
        map
    };
}

pub trait IntoRawControlVec {
    fn into(self) -> Vec<RawControl>;
}

impl IntoRawControlVec for Vec<RawControl> {
    fn into(self) -> Vec<RawControl> {
        self
    }
}

impl<R> IntoRawControlVec for R
where
    RawControl: From<R>,
{
    fn into(self) -> Vec<RawControl> {
        vec![std::convert::Into::into(self)]
    }
}

/// Mark a control as critical.
///
/// Most controls provided by this library implement this trait. All controls
/// are instantiated as non-critical by default, unless dictated otherwise by
/// their specification.
pub trait MakeCritical {
    /// Mark the control instance as critical. This operation consumes the control,
    /// and is irreversible.
    fn critical(self) -> CriticalControl<Self>
    where
        Self: Sized,
    {
        CriticalControl { control: self }
    }
}

/// Wrapper for a control marked as critical.
///
/// The wrapper ensures that the criticality of the control will be set to
/// true when the control is encoded.
pub struct CriticalControl<T> {
    control: T,
}

impl<T> From<CriticalControl<T>> for RawControl
where
    T: Into<RawControl>,
{
    fn from(cc: CriticalControl<T>) -> RawControl {
        let mut rc = cc.control.into();
        rc.crit = true;
        rc
    }
}

/// Conversion trait for response controls.
pub trait ControlParser {
    /// Convert the raw BER value into a control-specific struct.
    fn parse(val: &[u8]) -> Self;
}

/// Response control.
///
/// If the OID is recognized as corresponding to one of controls implemented by this
/// library while parsing raw BER data of the response, the first element will have
/// a value, otherwise it will be `None`.
#[derive(Clone, Debug)]
pub struct Control(pub Option<ControlType>, pub RawControl);

/// Generic control.
///
/// This struct can be used both for request and response controls. For requests, an
/// independently implemented control can produce an instance of this type and use it
/// to provide an element of the vector passed to
/// [`with_controls()`](../struct.LdapConn.html#method.with_controls) by calling
/// `into()` on the instance.
///
/// For responses, an instance is packed into a [`Control`](struct.Control.html) and
/// can be parsed by calling type-qualified [`parse()`](#method.parse) on that instance,
/// if a [`ControlParser`](trait.ControlParser.html) implementation exists for the
/// specified type.
#[derive(Clone, Debug)]
pub struct RawControl {
    /// OID of the control.
    pub ctype: String,
    /// Criticality, has no meaning on response.
    pub crit: bool,
    /// Raw value of the control, if any.
    pub val: Option<Vec<u8>>,
}

impl RawControl {
    /// Parse the generic control into a control-specific struct.
    ///
    /// The parser will panic if the control value is `None`.
    /// __Note__: no control known to the author signals the lack of return value by
    /// omitting the control value, so this shouldn't be a problem in practice.
    /// Nevertheless, it should be possible to report this along with other parsing errors,
    /// which is a planned future improvement.
    pub fn parse<T: ControlParser>(&self) -> T {
        T::parse(self.val.as_ref().expect("value"))
    }
}

pub fn build_tag(rc: RawControl) -> StructureTag {
    let mut seq = vec![Tag::OctetString(OctetString {
        inner: Vec::from(rc.ctype.as_bytes()),
        ..Default::default()
    })];
    if rc.crit {
        seq.push(Tag::Boolean(Boolean {
            inner: true,
            ..Default::default()
        }));
    }
    if let Some(val) = rc.val {
        seq.push(Tag::OctetString(OctetString {
            inner: val,
            ..Default::default()
        }));
    }
    Tag::Sequence(Sequence {
        inner: seq,
        ..Default::default()
    })
    .into_structure()
}

pub fn parse_controls(t: StructureTag) -> Vec<Control> {
    let tags = t.expect_constructed().expect("result sequence").into_iter();
    let mut ctrls = Vec::new();
    for ctrl in tags {
        let mut components = ctrl.expect_constructed().expect("components").into_iter();
        let ctype = String::from_utf8(
            components
                .next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("control type");
        let next = components.next();
        let (crit, maybe_val) = match next {
            None => (false, None),
            Some(c) => match c {
                StructureTag {
                    id, ref payload, ..
                } if id == Types::Boolean as u64 => match *payload {
                    PL::P(ref v) => (v[0] != 0, components.next()),
                    PL::C(_) => panic!("decoding error"),
                },
                StructureTag { id, .. } if id == Types::OctetString as u64 => {
                    (false, Some(c.clone()))
                }
                _ => panic!("decoding error"),
            },
        };
        let val = match maybe_val {
            None => None,
            Some(v) => Some(Vec::from(v.expect_primitive().expect("octet string"))),
        };
        let known_type = match CONTROLS.get(&*ctype) {
            Some(val) => Some(*val),
            None => None,
        };
        ctrls.push(Control(
            known_type,
            RawControl {
                ctype: ctype,
                crit: crit,
                val: val,
            },
        ));
    }
    ctrls
}
<|endoftext|>


<commit_before>use std::path::Path;

use sdl2::render::Texture;
use sdl2::image::LoadTexture;

use canvas::Canvas;

error_chain! {
    errors {
        TileWidthZero
        TileHeightZero
        FileNotFound
    }
}

pub struct SpriteSheet {
    tile_width: u32,
    tile_height: u32,
    image_frames: Vec<Texture>,
}

impl SpriteSheet {
    pub fn new(sheet_file: &str, tile_width: u32, tile_height: u32, canvas: &Canvas) -> Result<SpriteSheet> {
        let image_frames = Vec::new();

        let sheet = canvas.renderer.load_texture(Path::new(sheet_file))?;

        if tile_width <= 1 { return Err(ErrorKind::TileWidthZero.into()); }
        if tile_height <= 1 { return Err(ErrorKind::TileHeightZero.into()); }

        Ok(SpriteSheet {
            tile_width: tile_width,
            tile_height: tile_height,
            image_frames: image_frames,
        })
    }
}
<commit_msg>finish loading and splitting up of sprite sheet<commit_after>use std::path::Path;

use sdl2::render::Texture;
use sdl2::image::LoadTexture;
use sdl2::surface::Surface;
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;

use canvas::Canvas;

error_chain! {
    errors {
        TileWidthZero
        TileHeightZero
        TileWidthDoesntFit
        TileHeightDoesntFit
        FileNotFound
        RenderTargetError
        RenderTargetReserError
    }
}

pub struct SpriteSheet {
    tile_width: u32,
    tile_height: u32,
    image_frames: Vec<Texture>,
}

impl SpriteSheet {
    pub fn new(sheet_file: &str, tile_width: u32, tile_height: u32, canvas: &mut Canvas) -> Result<SpriteSheet> {
        let mut image_frames = Vec::new();

        if tile_width <= 1 { return Err(ErrorKind::TileWidthZero.into()); }
        if tile_height <= 1 { return Err(ErrorKind::TileHeightZero.into()); }

        let sheet = canvas.renderer.load_texture(Path::new(sheet_file))?;
        let properties = sheet.query();

        if properties.width % tile_width != 0 { return Err(ErrorKind::TileWidthDoesntFit.into()); }
        if properties.height % tile_height != 0 { return Err(ErrorKind::TileHeightDoesntFit.into()); }

        let mut x = 0;
        let mut y = 0;

        while x <= properties.width {
            while y <= properties.height {
                {
                    let mut render_target = canvas.renderer.render_target().ok_or(ErrorKind::RenderTargetError)?;
                    render_target.create_and_set(PixelFormatEnum::RGB24, tile_width,
                        tile_height).chain_err(|| "Could not create new texture from canvas renderer")?;
                }
                canvas.renderer.copy(&sheet, Some(Rect::new(x as i32, y as i32, tile_width, tile_height)), None);
                {
                    let mut render_target = canvas.renderer.render_target().ok_or(ErrorKind::RenderTargetError)?;
                    let new_texture = render_target.reset()?.ok_or(ErrorKind::RenderTargetReserError)?;
                    image_frames.push(new_texture);
                }

                x += tile_width;
                y += tile_height;
            }
        }

        Ok(SpriteSheet {
            tile_width: tile_width,
            tile_height: tile_height,
            image_frames: image_frames,
        })
    }
}
<|endoftext|>


<commit_before>use crate::algorithm::SigningAlgorithm;
use crate::error::Error;
use crate::header::Header;
use crate::signature::{Signed, Unsigned};
use crate::{ToBase64, Token, SEPARATOR};

pub trait SignWithKey {
    type Output;

    fn sign_with_key(self, key: &dyn SigningAlgorithm) -> Result<Self::Output, Error>;
}

impl<H, C> Token<H, C, Unsigned> {
    pub fn new(header: H, claims: C) -> Self {
        Token {
            header,
            claims,
            signature: Unsigned,
        }
    }

    pub fn header_mut(&mut self) -> &mut H {
        &mut self.header
    }

    pub fn claims_mut(&mut self) -> &mut C {
        &mut self.claims
    }
}

impl<H, C> Default for Token<H, C, Unsigned>
where
    H: Default,
    C: Default,
{
    fn default() -> Self {
        Token::new(H::default(), C::default())
    }
}

impl<H, C> SignWithKey for Token<H, C, Unsigned>
where
    H: ToBase64,
    C: ToBase64,
{
    type Output = Token<H, C, Signed>;

    fn sign_with_key(self, key: &dyn SigningAlgorithm) -> Result<Self::Output, Error> {
        let header = self.header.to_base64()?;
        let claims = self.claims.to_base64()?;
        let signature = key.sign(&header, &claims)?;

        let token_string = [&*header, &*claims, &signature].join(SEPARATOR);

        Ok(Token {
            header: self.header,
            claims: self.claims,
            signature: Signed { token_string },
        })
    }
}

impl<'a, H, C> Token<H, C, Signed> {
    pub fn as_str(&self) -> &str {
        &self.signature.token_string
    }
}

impl<H, C> Into<String> for Token<H, C, Signed> {
    fn into(self) -> String {
        self.signature.token_string
    }
}
<commit_msg>Add SignWithKey implementation for just claims<commit_after>use crate::algorithm::SigningAlgorithm;
use crate::error::Error;
use crate::header::Header;
use crate::signature::{Signed, Unsigned};
use crate::{ToBase64, Token, SEPARATOR};

pub trait SignWithKey {
    type Output;

    fn sign_with_key(self, key: &dyn SigningAlgorithm) -> Result<Self::Output, Error>;
}

impl<H, C> Token<H, C, Unsigned> {
    pub fn new(header: H, claims: C) -> Self {
        Token {
            header,
            claims,
            signature: Unsigned,
        }
    }

    pub fn header_mut(&mut self) -> &mut H {
        &mut self.header
    }

    pub fn claims_mut(&mut self) -> &mut C {
        &mut self.claims
    }
}

impl<H, C> Default for Token<H, C, Unsigned>
where
    H: Default,
    C: Default,
{
    fn default() -> Self {
        Token::new(H::default(), C::default())
    }
}

impl<C: ToBase64> SignWithKey for C {
    type Output = String;

    fn sign_with_key(self, key: &dyn SigningAlgorithm) -> Result<Self::Output, Error> {
        let header = Header {
            algorithm: key.algorithm_type(),
            ..Default::default()
        };

        let token = Token::new(header, self).sign_with_key(key)?;
        Ok(token.signature.token_string)
    }
}

impl<H, C> SignWithKey for Token<H, C, Unsigned>
where
    H: ToBase64,
    C: ToBase64,
{
    type Output = Token<H, C, Signed>;

    fn sign_with_key(self, key: &dyn SigningAlgorithm) -> Result<Self::Output, Error> {
        let header = self.header.to_base64()?;
        let claims = self.claims.to_base64()?;
        let signature = key.sign(&header, &claims)?;

        let token_string = [&*header, &*claims, &signature].join(SEPARATOR);

        Ok(Token {
            header: self.header,
            claims: self.claims,
            signature: Signed { token_string },
        })
    }
}

impl<'a, H, C> Token<H, C, Signed> {
    pub fn as_str(&self) -> &str {
        &self.signature.token_string
    }
}

impl<H, C> Into<String> for Token<H, C, Signed> {
    fn into(self) -> String {
        self.signature.token_string
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use super::allocator::Allocator;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    pub fn new<T: Allocator>(proto: JsProto, name: &str,
                             kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
                             allocator: &mut T) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                if let Some(ptr) = ptr {
                    allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key<T: Allocator>(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut T) {
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            match var.t {
                JsType::JsPtr(_) => allocator.condemn(var.unique.clone()).expect("Unable to whiten!"),
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}

#[cfg(test)]
mod tests {
    // TODO tests for objs
}
<commit_msg>silence warning<commit_after>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use super::allocator::Allocator;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new<T: Allocator>(proto: JsProto, name: &str,
                             kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
                             allocator: &mut T) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                if let Some(ptr) = ptr {
                    allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key<T: Allocator>(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut T) {
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            match var.t {
                JsType::JsPtr(_) => allocator.condemn(var.unique.clone()).expect("Unable to whiten!"),
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}

#[cfg(test)]
mod tests {
    // TODO tests for objs
}
<|endoftext|>