routing 0.4.0

A secured storage DHT
// Copyright 2015 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under (1) the MaidSafe.net Commercial License,
// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which
// licence you accepted on initial access to the Software (the "Licences").
//
// By contributing code to the SAFE Network Software, or to this project generally, you agree to be
// bound by the terms of the MaidSafe Contributor Agreement, version 1.0.  This, along with the
// Licenses can be found in the root directory of this project at LICENSE, COPYING and CONTRIBUTOR.
//
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.
//
// Please review the Licences for the specific language governing permissions and limitations
// relating to use of the SAFE Network Software.

/// Convert a u8 array to u8 vector.
pub fn array_as_vector(arr: &[u8]) -> Vec<u8> {
    let mut vector = Vec::new();
    for i in arr.iter() {
        vector.push(*i);
    }
    vector
}

/// Convert u8 vector to a fixed 64 byte size array.
pub fn vector_as_u8_64_array(vector: Vec<u8>) -> [u8; 64] {
    assert!(vector.len() >= 64);
    let mut arr = [0u8;64];
    for i in (0..64) {
        arr[i] = vector[i];
    }
    arr
}

/// Convert u8 vector to a fixed 32 byte size array.
pub fn vector_as_u8_32_array(vector: Vec<u8>) -> [u8; 32] {
    assert!(vector.len() >= 32);
    let mut arr = [0u8;32];
    for i in (0..32) {
        arr[i] = vector[i];
    }
    arr
}

/// Return a random vector of bytes of the given size.
pub fn generate_random_vec_u8(size: usize) -> Vec<u8> {
    let mut vec: Vec<u8> = Vec::with_capacity(size);
    for _ in 0..size {
        vec.push(::rand::random::<u8>());
    }
    vec
}

/// Group size.
pub static GROUP_SIZE: usize = 8;
/// Quorum size.
pub static QUORUM_SIZE: usize = 5;
/// Type definition.
pub type Bytes = Vec<u8>;

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, RustcEncodable, RustcDecodable)]
/// Address.
pub enum Address {
    /// Is a client with supplied public key.
    Client(::sodiumoxide::crypto::sign::PublicKey),
    /// Is a node with given name.
    Node(::NameType),
}

impl ::std::fmt::Debug for Address {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        match self {
            &Address::Client(ref public_key) => {
                formatter.write_str(&format!("Client({:?})", ::NameType::new(
                    ::sodiumoxide::crypto::hash::sha512::hash(&public_key[..]).0)))
            }
            &Address::Node(ref name) => {
                formatter.write_str(&format!("Node({:?})", name))
            }
        }
    }
}

#[derive(PartialEq, Eq, Clone, Debug)]
/// CacheOptions.
pub struct CacheOptions {
    cache_plain_data: bool,
    cache_structured_data: bool,
    cache_immutable_data: bool,
}

impl CacheOptions {

    /// Construct with caching off.
    pub fn no_caching() -> CacheOptions {
        CacheOptions {
            cache_plain_data: false,
            cache_structured_data: false,
            cache_immutable_data: false,
        }
    }

    /// Construct with caching optionally set.
    pub fn with_caching(cache_plain_data: bool, cache_structured_data: bool,
            cache_immutable_data: bool) -> CacheOptions {
        CacheOptions {
            cache_plain_data: cache_plain_data,
            cache_structured_data: cache_structured_data,
            cache_immutable_data: cache_immutable_data,
        }
    }

    /// Enable or disable Data caching.
    pub fn set_cache_options(&mut self, cache_options: CacheOptions) {
        self.cache_plain_data = cache_options.cache_plain_data;
        self.cache_structured_data = cache_options.cache_structured_data;
        self.cache_immutable_data = cache_options.cache_immutable_data;
    }

    /// Return true if any caching option is set otherwise false.
    pub fn caching_enabled(& self) -> bool {
        if self.cache_plain_data || self.cache_structured_data || self.cache_immutable_data {
            return true;
        }
        false
    }

    /// Return PlainData caching option.
    pub fn plain_data_caching_enabled(& self) -> bool {
        self.cache_plain_data
    }

    /// Return StructuredData caching option.
    pub fn structured_data_caching_enabled(& self) -> bool {
        self.cache_structured_data
    }

    /// Return ImmutableData caching option.
    pub fn immutable_data_caching_enabled(& self) -> bool {
        self.cache_immutable_data
    }
}

#[cfg(test)]
mod test {

    #[test]
    fn check_conversions() {
        let bytes: super::Bytes = super::generate_random_vec_u8(64);
        let array = super::vector_as_u8_64_array(bytes.clone());
        let vector = super::array_as_vector(&array);

        assert_eq!(64, vector.len());
        assert_eq!(bytes, vector);

        let bytes: super::Bytes = super::generate_random_vec_u8(32);
        let array = super::vector_as_u8_32_array(bytes.clone());
        let vector = super::array_as_vector(&array);

        assert_eq!(32, vector.len());
        assert_eq!(bytes, vector);
    }

    #[test]
    fn cache_options_no_caching() {
        let cache_options = super::CacheOptions::no_caching();

        assert!(!cache_options.plain_data_caching_enabled());
        assert!(!cache_options.structured_data_caching_enabled());
        assert!(!cache_options.immutable_data_caching_enabled());
        assert!(!cache_options.caching_enabled());
    }

    #[test]
    fn cache_options_with_caching() {
        let cache_options = super::CacheOptions::with_caching(true, true, true);

        assert!(cache_options.plain_data_caching_enabled());
        assert!(cache_options.structured_data_caching_enabled());
        assert!(cache_options.immutable_data_caching_enabled());
        assert!(cache_options.caching_enabled());
    }

    #[test]
    fn cache_options_set_options() {
        let mut cache_options = super::CacheOptions::with_caching(false, false, false);

        assert!(!cache_options.plain_data_caching_enabled());
        assert!(!cache_options.structured_data_caching_enabled());
        assert!(!cache_options.immutable_data_caching_enabled());
        assert!(!cache_options.caching_enabled());

        cache_options.set_cache_options(super::CacheOptions::with_caching(true, false, false));

        assert!(cache_options.plain_data_caching_enabled());
        assert!(!cache_options.structured_data_caching_enabled());
        assert!(!cache_options.immutable_data_caching_enabled());
        assert!(cache_options.caching_enabled());

        cache_options.set_cache_options(super::CacheOptions::with_caching(false, true, false));

        assert!(!cache_options.plain_data_caching_enabled());
        assert!(cache_options.structured_data_caching_enabled());
        assert!(!cache_options.immutable_data_caching_enabled());
        assert!(cache_options.caching_enabled());

        cache_options.set_cache_options(super::CacheOptions::with_caching(false, false, true));

        assert!(!cache_options.plain_data_caching_enabled());
        assert!(!cache_options.structured_data_caching_enabled());
        assert!(cache_options.immutable_data_caching_enabled());
        assert!(cache_options.caching_enabled());
    }

    #[test]
    fn address() {
        let sign_keys = ::sodiumoxide::crypto::sign::gen_keypair();
        let client_address = super::Address::Client(sign_keys.0);

        match client_address {
            super::Address::Client(public_sign_key) => assert_eq!(sign_keys.0, public_sign_key),
            _ => panic!("Unexpected error."),
        }

        let name: ::NameType = ::test_utils::Random::generate_random();
        let node_address = super::Address::Node(name);

        match node_address {
            super::Address::Node(node_name) => assert_eq!(name, node_name),
            _ => panic!("Unexpected error."),
        }
    }
}