<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

//! Handle wrapper for keysets.

use crate::{
    proto::{key_data::KeyMaterialType, Keyset, KeysetInfo},
    utils::wrap_err,
    TinkError,
};
use prost::Message;
use std::sync::Arc;

/// `Handle` provides access to a [`Keyset`] protobuf, to limit the exposure
/// of actual protocol buffers that hold sensitive key material.
pub struct Handle {
    ks: Keyset,
}

impl Handle {
    /// Create a keyset handle that contains a single fresh key generated according
    /// to the given [`KeyTemplate`](crate::proto::KeyTemplate).
    pub fn new(kt: &crate::proto::KeyTemplate) -> Result<Self, TinkError> {
        let mut ksm = super::Manager::new();
        ksm.rotate(kt)
            .map_err(|e| wrap_err("keyset::Handle: cannot generate new keyset", e))?;
        ksm.handle()
            .map_err(|e| wrap_err("keyset::Handle: cannot get keyset handle", e))
    }

    /// Create a new instance of [`Handle`] using the given [`Keyset`] which does not contain any
    /// secret key material.
    pub fn new_with_no_secrets(ks: Keyset) -> Result<Self, TinkError> {
        let h = Handle {
            ks: validate_keyset(ks)?,
        };
        if h.has_secrets()? {
            // If you need to do this, you have to use `tink::keyset::insecure::read()` instead.
            return Err("importing unencrypted secret key material is forbidden".into());
        }
        Ok(h)
    }

    /// Attempt to create a [`Handle`] from an encrypted keyset obtained via a
    /// [`Reader`](crate::keyset::Reader).
    pub fn read<T>(reader: &mut T, master_key: Box<dyn crate::Aead>) -> Result<Self, TinkError>
    where
        T: crate::keyset::Reader,
    {
        let encrypted_keyset = reader.read_encrypted()?;
        let ks = decrypt(&encrypted_keyset, master_key)?;
        Ok(Handle {
            ks: validate_keyset(ks)?,
        })
    }

    /// Attempt to create a [`Handle`] from a keyset obtained via a
    /// [`Reader`](crate::keyset::Reader).
    pub fn read_with_no_secrets<T>(reader: &mut T) -> Result<Self, TinkError>
    where
        T: crate::keyset::Reader,
    {
        let ks = reader.read()?;
        Handle::new_with_no_secrets(ks)
    }

    /// Return a [`Handle`] of the public keys if the managed keyset contains private keys.
    pub fn public(&self) -> Result<Self, TinkError> {
        let priv_keys = &self.ks.key;
        let mut pub_keys = Vec::with_capacity(priv_keys.len());
        for priv_key in priv_keys {
            let priv_key_data = priv_key
                .key_data
                .as_ref()
                .ok_or_else(|| TinkError::new("keyset::Handle: invalid keyset"))?;
            let pub_key_data =
                public_key_data(priv_key_data).map_err(|e| wrap_err("keyset::Handle", e))?;
            pub_keys.push(crate::proto::keyset::Key {
                key_data: Some(pub_key_data),
                status: priv_key.status,
                key_id: priv_key.key_id,
                output_prefix_type: priv_key.output_prefix_type,
            });
        }
        let ks = Keyset {
            primary_key_id: self.ks.primary_key_id,
            key: pub_keys,
        };
        Ok(Handle { ks })
    }

    /// Encrypts and writes the enclosed [`Keyset`].
    pub fn write<T>(
        &self,
        writer: &mut T,
        master_key: Box<dyn crate::Aead>,
    ) -> Result<(), TinkError>
    where
        T: super::Writer,
    {
        let encrypted = encrypt(&self.ks, master_key)?;
        writer.write_encrypted(&encrypted)
    }

    /// Export the keyset in `h` to the given [`Writer`](super::Writer) returning an error if the
    /// keyset contains secret key material.
    pub fn write_with_no_secrets<T>(&self, w: &mut T) -> Result<(), TinkError>
    where
        T: super::Writer,
    {
        if self.has_secrets()? {
            Err("exporting unencrypted secret key material is forbidden".into())
        } else {
            w.write(&self.ks)
        }
    }

    /// Create a set of primitives corresponding to the keys with status=ENABLED in the keyset of
    /// the given keyset [`Handle`], assuming all the corresponding key managers are present (keys
    /// with status!=ENABLED are skipped).
    ///
    /// The returned set is usually later "wrapped" into a class that implements the corresponding
    /// [`Primitive`](crate::Primitive) interface.
    pub fn primitives(&self) -> Result<crate::primitiveset::PrimitiveSet, TinkError> {
        self.primitives_with_key_manager(None)
    }

    /// Create a set of primitives corresponding to the keys with status=ENABLED in the keyset of
    /// the given keyset [`Handle`], using the given key manager (instead of registered key
    /// managers) for keys supported by it.  Keys not supported by the key manager are handled
    /// by matching registered key managers (if present), and keys with status!=ENABLED are
    /// skipped.
    ///
    /// This enables custom treatment of keys, for example providing extra context (e.g. credentials
    /// for accessing keys managed by a KMS), or gathering custom monitoring/profiling
    /// information.
    ///
    /// The returned set is usually later "wrapped" into a class that implements the corresponding
    /// [`Primitive`](crate::Primitive)-interface.
    pub fn primitives_with_key_manager(
        &self,
        km: Option<Arc<dyn crate::registry::KeyManager>>,
    ) -> Result<crate::primitiveset::PrimitiveSet, TinkError> {
        super::validate(&self.ks)
            .map_err(|e| wrap_err("primitives_with_key_manager: invalid keyset", e))?;
        let mut primitive_set = crate::primitiveset::PrimitiveSet::new();
        for key in &self.ks.key {
            if key.status != crate::proto::KeyStatusType::Enabled as i32 {
                continue;
            }
            let key_data = key
                .key_data
                .as_ref()
                .ok_or_else(|| TinkError::new("primitives_with_key_manager: no key_data"))?;
            let primitive = match &km {
                Some(km) if km.does_support(&key_data.type_url) => km.primitive(&key_data.value),
                Some(_) | None => crate::registry::primitive_from_key_data(&key_data),
            }
            .map_err(|e| {
                wrap_err(
                    "primitives_with_key_manager: cannot get primitive from key",
                    e,
                )
            })?;

            let entry = primitive_set
                .add(primitive, key)
                .map_err(|e| wrap_err("primitives_with_key_manager: cannot add primitive", e))?;
            if key.key_id == self.ks.primary_key_id {
                primitive_set.primary = Some(entry.clone());
            }
        }
        Ok(primitive_set)
    }

    /// Check if the keyset handle contains any key material considered secret.  Both symmetric keys
    /// and the private key of an asymmetric crypto system are considered secret keys. Also
    /// returns true when encountering any errors.
    fn has_secrets(&self) -> Result<bool, TinkError> {
        let mut result = false;
        for k in &self.ks.key {
            match &k.key_data {
                None => return Err("invalid keyset".into()),
                Some(kd) => match KeyMaterialType::from_i32(kd.key_material_type) {
                    Some(KeyMaterialType::UnknownKeymaterial) => result = true,
                    Some(KeyMaterialType::Symmetric) => result = true,
                    Some(KeyMaterialType::AsymmetricPrivate) => result = true,
                    Some(KeyMaterialType::AsymmetricPublic) => {}
                    Some(KeyMaterialType::Remote) => {}
                    None => return Err("invalid key material type".into()),
                },
            }
        }
        Ok(result)
    }

    /// Return [`KeysetInfo`] representation of the managed keyset. The result does not
    /// contain any sensitive key material.
    pub fn keyset_info(&self) -> KeysetInfo {
        get_keyset_info(&self.ks)
    }

    /// Consume the `Handle` and return the enclosed [`Keyset`].
    pub(crate) fn into_inner(self) -> Keyset {
        self.ks
    }

    /// Return a copy of the enclosed [`Keyset`]; for internal
    /// use only.
    pub(crate) fn clone_keyset(&self) -> Keyset {
        self.ks.clone()
    }

    /// Create a `Handle` from a [`Keyset`].  Implemented as a standalone method rather than
    /// as an `impl` of the `From` trait so visibility can be restricted.
    pub(crate) fn from_keyset(ks: Keyset) -> Result<Self, TinkError> {
        Ok(Handle {
            ks: validate_keyset(ks)?,
        })
    }
}

/// Check that a [`Keyset`] is valid.
fn validate_keyset(ks: Keyset) -> Result<Keyset, TinkError> {
    for k in &ks.key {
        match &k.key_data {
            None if k.status == crate::proto::KeyStatusType::Destroyed as i32 => {}
            None => return Err("invalid keyset".into()),
            Some(kd) => match KeyMaterialType::from_i32(kd.key_material_type) {
                Some(_) => {}
                None => return Err("invalid key material type".into()),
            },
        }
    }
    Ok(ks)
}

/// Extract the public key data corresponding to private key data.
fn public_key_data(
    priv_key_data: &crate::proto::KeyData,
) -> Result<crate::proto::KeyData, TinkError> {
    if priv_key_data.key_material_type
        != crate::proto::key_data::KeyMaterialType::AsymmetricPrivate as i32
    {
        return Err("keyset::Handle: keyset contains a non-private key".into());
    }
    let km = crate::registry::get_key_manager(&priv_key_data.type_url)?;

    if !km.supports_private_keys() {
        return Err(format!(
            "keyset::Handle: {} does not belong to a KeyManager that handles private keys",
            priv_key_data.type_url
        )
        .into());
    }
    km.public_key_data(&priv_key_data.value)
}

/// Decrypt a keyset with a master key.
fn decrypt(
    encrypted_keyset: &crate::proto::EncryptedKeyset,
    master_key: Box<dyn crate::Aead>,
) -> Result<Keyset, TinkError> {
    let decrypted = master_key
        .decrypt(&encrypted_keyset.encrypted_keyset, &[])
        .map_err(|e| wrap_err("keyset::Handle: decryption failed", e))?;
    Keyset::decode(&decrypted[..]).map_err(|_| TinkError::new("keyset::Handle:: invalid keyset"))
}

/// Encrypt a keyset with a master key.
fn encrypt(
    keyset: &Keyset,
    master_key: Box<dyn crate::Aead>,
) -> Result<crate::proto::EncryptedKeyset, TinkError> {
    let mut serialized_keyset = vec![];
    keyset
        .encode(&mut serialized_keyset)
        .map_err(|e| wrap_err("keyset::Handle: invalid keyset", e))?;
    let encrypted = master_key
        .encrypt(&serialized_keyset, &[])
        .map_err(|e| wrap_err("keyset::Handle: encrypted failed", e))?;
    Ok(crate::proto::EncryptedKeyset {
        encrypted_keyset: encrypted,
        keyset_info: Some(get_keyset_info(keyset)),
    })
}

/// Return a [`KeysetInfo`] from a [`Keyset`] protobuf.
fn get_keyset_info(keyset: &Keyset) -> KeysetInfo {
    let n_key = keyset.key.len();
    let mut key_infos = Vec::with_capacity(n_key);
    for key in &keyset.key {
        key_infos.push(get_key_info(key));
    }
    KeysetInfo {
        primary_key_id: keyset.primary_key_id,
        key_info: key_infos,
    }
}

/// Return a [`KeyInfo`](crate::proto::keyset_info::KeyInfo) from a
/// [`Key`](crate::proto::keyset::Key) protobuf.
fn get_key_info(key: &crate::proto::keyset::Key) -> crate::proto::keyset_info::KeyInfo {
    crate::proto::keyset_info::KeyInfo {
        type_url: match &key.key_data {
            Some(kd) => kd.type_url.clone(),
            None => "".to_string(),
        },
        status: key.status,
        key_id: key.key_id,
        output_prefix_type: key.output_prefix_type,
    }
}

impl std::fmt::Debug for Handle {
    /// Return a string representation of the managed keyset.
    /// The result does not contain any sensitive key material.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", get_keyset_info(&self.ks))
    }
}
<commit_msg>tink::keyset: feature-protect method<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

//! Handle wrapper for keysets.

use crate::{
    proto::{key_data::KeyMaterialType, Keyset, KeysetInfo},
    utils::wrap_err,
    TinkError,
};
use prost::Message;
use std::sync::Arc;

/// `Handle` provides access to a [`Keyset`] protobuf, to limit the exposure
/// of actual protocol buffers that hold sensitive key material.
pub struct Handle {
    ks: Keyset,
}

impl Handle {
    /// Create a keyset handle that contains a single fresh key generated according
    /// to the given [`KeyTemplate`](crate::proto::KeyTemplate).
    pub fn new(kt: &crate::proto::KeyTemplate) -> Result<Self, TinkError> {
        let mut ksm = super::Manager::new();
        ksm.rotate(kt)
            .map_err(|e| wrap_err("keyset::Handle: cannot generate new keyset", e))?;
        ksm.handle()
            .map_err(|e| wrap_err("keyset::Handle: cannot get keyset handle", e))
    }

    /// Create a new instance of [`Handle`] using the given [`Keyset`] which does not contain any
    /// secret key material.
    pub fn new_with_no_secrets(ks: Keyset) -> Result<Self, TinkError> {
        let h = Handle {
            ks: validate_keyset(ks)?,
        };
        if h.has_secrets()? {
            // If you need to do this, you have to use `tink::keyset::insecure::read()` instead.
            return Err("importing unencrypted secret key material is forbidden".into());
        }
        Ok(h)
    }

    /// Attempt to create a [`Handle`] from an encrypted keyset obtained via a
    /// [`Reader`](crate::keyset::Reader).
    pub fn read<T>(reader: &mut T, master_key: Box<dyn crate::Aead>) -> Result<Self, TinkError>
    where
        T: crate::keyset::Reader,
    {
        let encrypted_keyset = reader.read_encrypted()?;
        let ks = decrypt(&encrypted_keyset, master_key)?;
        Ok(Handle {
            ks: validate_keyset(ks)?,
        })
    }

    /// Attempt to create a [`Handle`] from a keyset obtained via a
    /// [`Reader`](crate::keyset::Reader).
    pub fn read_with_no_secrets<T>(reader: &mut T) -> Result<Self, TinkError>
    where
        T: crate::keyset::Reader,
    {
        let ks = reader.read()?;
        Handle::new_with_no_secrets(ks)
    }

    /// Return a [`Handle`] of the public keys if the managed keyset contains private keys.
    pub fn public(&self) -> Result<Self, TinkError> {
        let priv_keys = &self.ks.key;
        let mut pub_keys = Vec::with_capacity(priv_keys.len());
        for priv_key in priv_keys {
            let priv_key_data = priv_key
                .key_data
                .as_ref()
                .ok_or_else(|| TinkError::new("keyset::Handle: invalid keyset"))?;
            let pub_key_data =
                public_key_data(priv_key_data).map_err(|e| wrap_err("keyset::Handle", e))?;
            pub_keys.push(crate::proto::keyset::Key {
                key_data: Some(pub_key_data),
                status: priv_key.status,
                key_id: priv_key.key_id,
                output_prefix_type: priv_key.output_prefix_type,
            });
        }
        let ks = Keyset {
            primary_key_id: self.ks.primary_key_id,
            key: pub_keys,
        };
        Ok(Handle { ks })
    }

    /// Encrypts and writes the enclosed [`Keyset`].
    pub fn write<T>(
        &self,
        writer: &mut T,
        master_key: Box<dyn crate::Aead>,
    ) -> Result<(), TinkError>
    where
        T: super::Writer,
    {
        let encrypted = encrypt(&self.ks, master_key)?;
        writer.write_encrypted(&encrypted)
    }

    /// Export the keyset in `h` to the given [`Writer`](super::Writer) returning an error if the
    /// keyset contains secret key material.
    pub fn write_with_no_secrets<T>(&self, w: &mut T) -> Result<(), TinkError>
    where
        T: super::Writer,
    {
        if self.has_secrets()? {
            Err("exporting unencrypted secret key material is forbidden".into())
        } else {
            w.write(&self.ks)
        }
    }

    /// Create a set of primitives corresponding to the keys with status=ENABLED in the keyset of
    /// the given keyset [`Handle`], assuming all the corresponding key managers are present (keys
    /// with status!=ENABLED are skipped).
    ///
    /// The returned set is usually later "wrapped" into a class that implements the corresponding
    /// [`Primitive`](crate::Primitive) interface.
    pub fn primitives(&self) -> Result<crate::primitiveset::PrimitiveSet, TinkError> {
        self.primitives_with_key_manager(None)
    }

    /// Create a set of primitives corresponding to the keys with status=ENABLED in the keyset of
    /// the given keyset [`Handle`], using the given key manager (instead of registered key
    /// managers) for keys supported by it.  Keys not supported by the key manager are handled
    /// by matching registered key managers (if present), and keys with status!=ENABLED are
    /// skipped.
    ///
    /// This enables custom treatment of keys, for example providing extra context (e.g. credentials
    /// for accessing keys managed by a KMS), or gathering custom monitoring/profiling
    /// information.
    ///
    /// The returned set is usually later "wrapped" into a class that implements the corresponding
    /// [`Primitive`](crate::Primitive)-interface.
    pub fn primitives_with_key_manager(
        &self,
        km: Option<Arc<dyn crate::registry::KeyManager>>,
    ) -> Result<crate::primitiveset::PrimitiveSet, TinkError> {
        super::validate(&self.ks)
            .map_err(|e| wrap_err("primitives_with_key_manager: invalid keyset", e))?;
        let mut primitive_set = crate::primitiveset::PrimitiveSet::new();
        for key in &self.ks.key {
            if key.status != crate::proto::KeyStatusType::Enabled as i32 {
                continue;
            }
            let key_data = key
                .key_data
                .as_ref()
                .ok_or_else(|| TinkError::new("primitives_with_key_manager: no key_data"))?;
            let primitive = match &km {
                Some(km) if km.does_support(&key_data.type_url) => km.primitive(&key_data.value),
                Some(_) | None => crate::registry::primitive_from_key_data(&key_data),
            }
            .map_err(|e| {
                wrap_err(
                    "primitives_with_key_manager: cannot get primitive from key",
                    e,
                )
            })?;

            let entry = primitive_set
                .add(primitive, key)
                .map_err(|e| wrap_err("primitives_with_key_manager: cannot add primitive", e))?;
            if key.key_id == self.ks.primary_key_id {
                primitive_set.primary = Some(entry.clone());
            }
        }
        Ok(primitive_set)
    }

    /// Check if the keyset handle contains any key material considered secret.  Both symmetric keys
    /// and the private key of an asymmetric crypto system are considered secret keys. Also
    /// returns true when encountering any errors.
    fn has_secrets(&self) -> Result<bool, TinkError> {
        let mut result = false;
        for k in &self.ks.key {
            match &k.key_data {
                None => return Err("invalid keyset".into()),
                Some(kd) => match KeyMaterialType::from_i32(kd.key_material_type) {
                    Some(KeyMaterialType::UnknownKeymaterial) => result = true,
                    Some(KeyMaterialType::Symmetric) => result = true,
                    Some(KeyMaterialType::AsymmetricPrivate) => result = true,
                    Some(KeyMaterialType::AsymmetricPublic) => {}
                    Some(KeyMaterialType::Remote) => {}
                    None => return Err("invalid key material type".into()),
                },
            }
        }
        Ok(result)
    }

    /// Return [`KeysetInfo`] representation of the managed keyset. The result does not
    /// contain any sensitive key material.
    pub fn keyset_info(&self) -> KeysetInfo {
        get_keyset_info(&self.ks)
    }

    /// Consume the `Handle` and return the enclosed [`Keyset`].
    pub(crate) fn into_inner(self) -> Keyset {
        self.ks
    }

    /// Return a copy of the enclosed [`Keyset`]; for internal
    /// use only.
    #[cfg(feature = "insecure")]
    pub(crate) fn clone_keyset(&self) -> Keyset {
        self.ks.clone()
    }

    /// Create a `Handle` from a [`Keyset`].  Implemented as a standalone method rather than
    /// as an `impl` of the `From` trait so visibility can be restricted.
    pub(crate) fn from_keyset(ks: Keyset) -> Result<Self, TinkError> {
        Ok(Handle {
            ks: validate_keyset(ks)?,
        })
    }
}

/// Check that a [`Keyset`] is valid.
fn validate_keyset(ks: Keyset) -> Result<Keyset, TinkError> {
    for k in &ks.key {
        match &k.key_data {
            None if k.status == crate::proto::KeyStatusType::Destroyed as i32 => {}
            None => return Err("invalid keyset".into()),
            Some(kd) => match KeyMaterialType::from_i32(kd.key_material_type) {
                Some(_) => {}
                None => return Err("invalid key material type".into()),
            },
        }
    }
    Ok(ks)
}

/// Extract the public key data corresponding to private key data.
fn public_key_data(
    priv_key_data: &crate::proto::KeyData,
) -> Result<crate::proto::KeyData, TinkError> {
    if priv_key_data.key_material_type
        != crate::proto::key_data::KeyMaterialType::AsymmetricPrivate as i32
    {
        return Err("keyset::Handle: keyset contains a non-private key".into());
    }
    let km = crate::registry::get_key_manager(&priv_key_data.type_url)?;

    if !km.supports_private_keys() {
        return Err(format!(
            "keyset::Handle: {} does not belong to a KeyManager that handles private keys",
            priv_key_data.type_url
        )
        .into());
    }
    km.public_key_data(&priv_key_data.value)
}

/// Decrypt a keyset with a master key.
fn decrypt(
    encrypted_keyset: &crate::proto::EncryptedKeyset,
    master_key: Box<dyn crate::Aead>,
) -> Result<Keyset, TinkError> {
    let decrypted = master_key
        .decrypt(&encrypted_keyset.encrypted_keyset, &[])
        .map_err(|e| wrap_err("keyset::Handle: decryption failed", e))?;
    Keyset::decode(&decrypted[..]).map_err(|_| TinkError::new("keyset::Handle:: invalid keyset"))
}

/// Encrypt a keyset with a master key.
fn encrypt(
    keyset: &Keyset,
    master_key: Box<dyn crate::Aead>,
) -> Result<crate::proto::EncryptedKeyset, TinkError> {
    let mut serialized_keyset = vec![];
    keyset
        .encode(&mut serialized_keyset)
        .map_err(|e| wrap_err("keyset::Handle: invalid keyset", e))?;
    let encrypted = master_key
        .encrypt(&serialized_keyset, &[])
        .map_err(|e| wrap_err("keyset::Handle: encrypted failed", e))?;
    Ok(crate::proto::EncryptedKeyset {
        encrypted_keyset: encrypted,
        keyset_info: Some(get_keyset_info(keyset)),
    })
}

/// Return a [`KeysetInfo`] from a [`Keyset`] protobuf.
fn get_keyset_info(keyset: &Keyset) -> KeysetInfo {
    let n_key = keyset.key.len();
    let mut key_infos = Vec::with_capacity(n_key);
    for key in &keyset.key {
        key_infos.push(get_key_info(key));
    }
    KeysetInfo {
        primary_key_id: keyset.primary_key_id,
        key_info: key_infos,
    }
}

/// Return a [`KeyInfo`](crate::proto::keyset_info::KeyInfo) from a
/// [`Key`](crate::proto::keyset::Key) protobuf.
fn get_key_info(key: &crate::proto::keyset::Key) -> crate::proto::keyset_info::KeyInfo {
    crate::proto::keyset_info::KeyInfo {
        type_url: match &key.key_data {
            Some(kd) => kd.type_url.clone(),
            None => "".to_string(),
        },
        status: key.status,
        key_id: key.key_id,
        output_prefix_type: key.output_prefix_type,
    }
}

impl std::fmt::Debug for Handle {
    /// Return a string representation of the managed keyset.
    /// The result does not contain any sensitive key material.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", get_keyset_info(&self.ks))
    }
}
<|endoftext|>


<commit_before>//! Unix domain socket utility types

pub mod datagram;

pub(crate) mod listener;

mod split;
pub use split::{ReadHalf, WriteHalf};

mod split_owned;
pub use split_owned::{OwnedReadHalf, OwnedWriteHalf, ReuniteError};

mod socketaddr;
pub use socketaddr::SocketAddr;

pub(crate) mod stream;
pub(crate) use stream::UnixStream;

mod ucred;
pub use ucred::UCred;
<commit_msg>net: hide net::unix::datagram module from docs (#3775)<commit_after>//! Unix domain socket utility types

// This module does not currently provide any public API, but it was
// unintentionally defined as a public module. Hide it from the documentation
// instead of changing it to a private module to avoid breakage.
#[doc(hidden)]
pub mod datagram;

pub(crate) mod listener;

mod split;
pub use split::{ReadHalf, WriteHalf};

mod split_owned;
pub use split_owned::{OwnedReadHalf, OwnedWriteHalf, ReuniteError};

mod socketaddr;
pub use socketaddr::SocketAddr;

pub(crate) mod stream;
pub(crate) use stream::UnixStream;

mod ucred;
pub use ucred::UCred;
<|endoftext|>


<commit_before>extern crate gcc;
extern crate syntex_syntax as syntax;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::*;
use std::iter;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::attr::{self, ReprAttr};
use syntax::parse::{self, ParseSess};
use syntax::visit::{self, Visitor};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct TestGenerator<'a> {
    target: String,
    rust: Box<Write>,
    c: Box<Write>,
    sh: &'a SpanHandler,
    structs: HashSet<String>,
}

struct StructFinder {
    structs: HashSet<String>,
}

impl<'a> TestGenerator<'a> {
    fn defines(&self) -> Vec<&'static str> {
        let mut ret = Vec::new();
        if self.target.contains("unknown-linux") {
            ret.push("_GNU_SOURCE");
        }
        if self.target.contains("msvc") {
            ret.push("alignof __alignof");
        }
        return ret
    }

    fn headers(&self) -> Vec<&'static str> {
        let mut base = Vec::new();

        if self.target.contains("windows") {
            base.push("windows.h");
        }

        base.extend(&[
            "errno.h",
            "fcntl.h",
            "limits.h",
            "stddef.h",
            "stdint.h",
            "stdio.h",
            "stdlib.h",
            "sys/stat.h",
            "sys/types.h",
            "time.h",
            "wchar.h",
        ]);

        if self.target.contains("apple-darwin") {
            base.push("mach/mach_time.h");
        }

        if self.target.contains("unknown-linux") {
            base.push("linux/if_packet.h");
            base.push("net/ethernet.h");
        }

        if self.target.contains("windows") {
            base.push("ws2tcpip.h");
        } else {
            base.push("glob.h");
            base.push("ifaddrs.h");
            base.push("net/if.h");
            base.push("netdb.h");
            base.push("netinet/in.h");
            base.push("netinet/ip.h");
            base.push("netinet/tcp.h");
            base.push("pthread.h");
            base.push("signal.h");
            base.push("stdalign.h");
            base.push("sys/mman.h");
            base.push("sys/resource.h");
            base.push("sys/socket.h");
            base.push("sys/time.h");
            base.push("sys/un.h");
            base.push("utime.h");
            base.push("unistd.h");
        }

        return base
    }

    fn rust2c(&self, ty: &str) -> String {
        match ty {
            t if t.starts_with("c_") => {
                match &ty[2..].replace("long", " long")[..] {
                    s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
                    "short" => format!("short"),
                    s if s.starts_with("s") => format!("signed {}", &s[1..]),
                    s => s.to_string(),
                }
            }
            "ip6_mreq" => "struct ipv6_mreq".to_string(),
            "glob_t" => "glob_t".to_string(),
            t if t.starts_with("pthread") => t.to_string(),

            t if self.structs.contains(t) => format!("struct {}", t),

            t => t.to_string(),
        }
    }

    fn rust2cfield(&self, struct_: &str, field: &str) -> String {
        match field {
            s if s.ends_with("_nsec") && struct_ == "stat" => {
                if self.target.contains("apple-darwin") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    }

    fn cfg_list(&self) -> Vec<(&'static str, Option<&'static str>)> {
        let mut ret = Vec::new();
        let (arch, target_pointer_width) = if self.target.starts_with("x86_64") {
            ("x86_64", "64")
        } else if self.target.starts_with("i686") {
            ("x86", "32")
        } else {
            panic!("unknown arch/pointer width: {}", self.target)
        };
        let (os, family, env) = if self.target.contains("unknown-linux") {
            ("linux", "unix", "gnu")
        } else if self.target.contains("apple-darwin") {
            ("macos", "unix", "")
        } else if self.target.contains("windows-msvc") {
            ("windows", "windows", "msvc")
        } else if self.target.contains("windows-gnu") {
            ("windows", "windows", "gnu")
        } else {
            panic!("unknown os/family width: {}", self.target)
        };

        ret.push((family, None));
        ret.push(("target_os", Some(os)));
        ret.push(("target_family", Some(family)));
        ret.push(("target_arch", Some(arch)));
        // skip endianness
        ret.push(("target_pointer_width", Some(target_pointer_width)));
        ret.push(("target_env", Some(env)));

        return ret
    }
}

fn main() {
    // Prep the test generator
    let target = t!(env::var("TARGET"));
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let rust_out = BufWriter::new(t!(File::create(out.join("all.rs"))));
    let c_out = BufWriter::new(t!(File::create(out.join("all.c"))));
    let sess = ParseSess::new();
    let mut tg = TestGenerator {
        target: target,
        rust: Box::new(rust_out),
        c: Box::new(c_out),
        sh: &sess.span_diagnostic,
        structs: HashSet::new(),
    };

    // Parse the libc crate
    let src = Path::new("../src/lib.rs");
    let cfg = Vec::new();
    let mut krate = parse::parse_crate_from_file(src, cfg, &sess);

    // Strip the crate down to just what's configured for our target
    for (k, v) in tg.cfg_list() {
        let s = InternedString::new;
        krate.config.push(match v {
            Some(v) => attr::mk_name_value_item_str(s(k), s(v)),
            None => attr::mk_word_item(s(k)),
        });
    }
    let mut gated_cfgs = Vec::new();
    let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
                                                         krate,
                                                         &mut gated_cfgs);

    // Probe the crate to find all structs (used to convert type names to names
    // in C).
    let mut structs = StructFinder {
        structs: HashSet::new(),
    };
    visit::walk_crate(&mut structs, &krate);
    tg.structs = structs.structs;

    // Prep the C file by emitting header stuff
    for define in tg.defines() {
        t!(writeln!(tg.c, "#define {}", define));
    }
    for header in tg.headers() {
        t!(writeln!(tg.c, "#include <{}>", header));
    }

    // Walk the crate, emitting test cases for everything found
    visit::walk_crate(&mut tg, &krate);

    // Compile our C shim to be linked into tests
    let mut cfg = gcc::Config::new();
    cfg.file(out.join("all.c"));

    if tg.target.contains("msvc") {
        cfg.flag("/W3").flag("/Wall").flag("/WX");
    } else {
        cfg.flag("-Wall").flag("-Wextra").flag("-Werror")
           .arg("-Wno-unused-parameter");
    }

    drop(tg);
    cfg.compile("liball.a");
}

impl<'a> TestGenerator<'a> {
    fn test_type(&mut self, ty: &str) {
        match ty {
            "sighandler_t" => return,
            _ => {}
        }
        let c = self.rust2c(ty);
        self.test_size_align(ty, &c);
    }

    fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
        let cty = self.rust2c(ty);
        self.test_size_align(ty, &cty);

        t!(writeln!(self.rust, r#"
            #[test]
            fn field_offset_size_{ty}() {{
        "#, ty = ty));
        for field in s.fields.iter() {
            let name = match field.node.kind {
                ast::NamedField(name, ast::Public) => name,
                ast::NamedField(_, ast::Inherited) => continue,
                ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
            };

            let cfield = self.rust2cfield(ty, &name.to_string());

            t!(writeln!(self.c, r#"
                uint64_t __test_offset_{ty}_{rust_field}() {{
                    return offsetof({cty}, {c_field});
                }}
                uint64_t __test_size_{ty}_{rust_field}() {{
                    {cty}* foo = NULL;
                    return sizeof(foo->{c_field});
                }}
            "#, ty = ty, cty = cty, rust_field = name, c_field = cfield));
            t!(writeln!(self.rust, r#"
                extern {{
                    fn __test_offset_{ty}_{field}() -> u64;
                    fn __test_size_{ty}_{field}() -> u64;
                }}
                unsafe {{
                    let foo = 0 as *const {ty};
                    same(offset_of!({ty}, {field}),
                         __test_offset_{ty}_{field}(),
                         "field offset {field} of {ty}");
                    same(mem::size_of_val(&(*foo).{field}) as u64,
                         __test_size_{ty}_{field}(),
                         "field size {field} of {ty}");
                }}
            "#, ty = ty, field = name));
        }
        t!(writeln!(self.rust, r#"
            }}
        "#));
    }

    fn test_size_align(&mut self, rust: &str, c: &str) {
        t!(writeln!(self.c, r#"
            uint64_t __test_size_{ty}() {{ return sizeof({cty}); }}
            uint64_t __test_align_{ty}() {{ return alignof({cty}); }}
        "#, ty = rust, cty = c));
        t!(writeln!(self.rust, r#"
            #[test]
            fn size_align_{ty}() {{
                extern {{
                    fn __test_size_{ty}() -> u64;
                    fn __test_align_{ty}() -> u64;
                }}
                unsafe {{
                    same(mem::size_of::<{ty}>() as u64,
                         __test_size_{ty}(), "size");
                    same(align::<{ty}>() as u64,
                         __test_align_{ty}(), "align");
                }}
            }}
        "#, ty = rust));
    }

    fn test_const(&mut self, name: &str, rust_ty: &str) {
        let cty = self.rust2c(&rust_ty.replace("*mut ", "")
                                      .replace("*const ", ""));
        let ptrs = rust_ty.matches("*").count();
        let cty = format!("{}{}", cty,
                          iter::repeat("*").take(ptrs).collect::<String>());
        let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
        t!(writeln!(self.c, r#"
            int __test_const_{name}({cty} *out) {{
                int ret = 0;
                #if defined({name})
                    *out = {cast}({name});
                    ret = 1;
                #endif
                return ret;
            }}
        "#, name = name, cast = cast, cty = cty));
        t!(writeln!(self.rust, r#"
            #[test]
            fn const_{name}() {{
                extern {{
                    fn __test_const_{name}(out: *mut {ty}) -> c_int;
                }}
                unsafe {{
                    let mut o = mem::zeroed();
                    if __test_const_{name}(&mut o) == 0 {{
                        panic!("not defined");
                    }} else {{
                        same({name}, o, "value");
                    }}
                }}
            }}
        "#, ty = rust_ty, name = name));
    }

    fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
         assert!(generics.lifetimes.len() == 0);
         assert!(generics.ty_params.len() == 0);
         assert!(generics.where_clause.predicates.len() == 0);
    }

    fn ty2name(&self, ty: &ast::Ty) -> String {
        match ty.node {
            ast::TyPath(_, ref path) => {
                path.segments.last().unwrap().identifier.to_string()
            }
            ast::TyPtr(ref t) => {
                format!("*{} {}", match t.mutbl {
                    ast::MutImmutable => "const",
                    ast::MutMutable => "mut",
                }, self.ty2name(&t.ty))
            }
            _ => panic!("unknown ty {:?}", ty),
        }
    }
}

impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemTy(_, ref generics) => {
                 self.assert_no_generics(i, generics);
                 self.test_type(&i.ident.to_string());
             }

             ast::ItemStruct(ref s, ref generics) => {
                 self.assert_no_generics(i, generics);
                 let is_c = i.attrs.iter().any(|a| {
                    attr::find_repr_attrs(self.sh, a).iter().any(|a| {
                        *a == ReprAttr::ReprExtern
                    })
                 });
                 if !is_c {
                     panic!("{} is not marked #[repr(C)]", i.ident);
                 }
                 self.test_struct(&i.ident.to_string(), s);
             }

             ast::ItemConst(ref ty, _) => {
                 let ty = self.ty2name(ty);
                 self.test_const(&i.ident.to_string(), &ty);
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}

impl<'v> Visitor<'v> for StructFinder {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemStruct(..) => {
                 self.structs.insert(i.ident.to_string());
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}
<commit_msg>No parameters in C<commit_after>extern crate gcc;
extern crate syntex_syntax as syntax;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::*;
use std::iter;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::attr::{self, ReprAttr};
use syntax::parse::{self, ParseSess};
use syntax::visit::{self, Visitor};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct TestGenerator<'a> {
    target: String,
    rust: Box<Write>,
    c: Box<Write>,
    sh: &'a SpanHandler,
    structs: HashSet<String>,
}

struct StructFinder {
    structs: HashSet<String>,
}

impl<'a> TestGenerator<'a> {
    fn defines(&self) -> Vec<&'static str> {
        let mut ret = Vec::new();
        if self.target.contains("unknown-linux") {
            ret.push("_GNU_SOURCE");
        }
        if self.target.contains("msvc") {
            ret.push("alignof __alignof");
        }
        return ret
    }

    fn headers(&self) -> Vec<&'static str> {
        let mut base = Vec::new();

        if self.target.contains("windows") {
            base.push("windows.h");
        }

        base.extend(&[
            "errno.h",
            "fcntl.h",
            "limits.h",
            "stddef.h",
            "stdint.h",
            "stdio.h",
            "stdlib.h",
            "sys/stat.h",
            "sys/types.h",
            "time.h",
            "wchar.h",
        ]);

        if self.target.contains("apple-darwin") {
            base.push("mach/mach_time.h");
        }

        if self.target.contains("unknown-linux") {
            base.push("linux/if_packet.h");
            base.push("net/ethernet.h");
        }

        if self.target.contains("windows") {
            base.push("ws2tcpip.h");
        } else {
            base.push("glob.h");
            base.push("ifaddrs.h");
            base.push("net/if.h");
            base.push("netdb.h");
            base.push("netinet/in.h");
            base.push("netinet/ip.h");
            base.push("netinet/tcp.h");
            base.push("pthread.h");
            base.push("signal.h");
            base.push("stdalign.h");
            base.push("sys/mman.h");
            base.push("sys/resource.h");
            base.push("sys/socket.h");
            base.push("sys/time.h");
            base.push("sys/un.h");
            base.push("utime.h");
            base.push("unistd.h");
        }

        return base
    }

    fn rust2c(&self, ty: &str) -> String {
        match ty {
            t if t.starts_with("c_") => {
                match &ty[2..].replace("long", " long")[..] {
                    s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
                    "short" => format!("short"),
                    s if s.starts_with("s") => format!("signed {}", &s[1..]),
                    s => s.to_string(),
                }
            }
            "ip6_mreq" => "struct ipv6_mreq".to_string(),
            "glob_t" => "glob_t".to_string(),
            t if t.starts_with("pthread") => t.to_string(),

            t if self.structs.contains(t) => format!("struct {}", t),

            t => t.to_string(),
        }
    }

    fn rust2cfield(&self, struct_: &str, field: &str) -> String {
        match field {
            s if s.ends_with("_nsec") && struct_ == "stat" => {
                if self.target.contains("apple-darwin") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    }

    fn cfg_list(&self) -> Vec<(&'static str, Option<&'static str>)> {
        let mut ret = Vec::new();
        let (arch, target_pointer_width) = if self.target.starts_with("x86_64") {
            ("x86_64", "64")
        } else if self.target.starts_with("i686") {
            ("x86", "32")
        } else {
            panic!("unknown arch/pointer width: {}", self.target)
        };
        let (os, family, env) = if self.target.contains("unknown-linux") {
            ("linux", "unix", "gnu")
        } else if self.target.contains("apple-darwin") {
            ("macos", "unix", "")
        } else if self.target.contains("windows-msvc") {
            ("windows", "windows", "msvc")
        } else if self.target.contains("windows-gnu") {
            ("windows", "windows", "gnu")
        } else {
            panic!("unknown os/family width: {}", self.target)
        };

        ret.push((family, None));
        ret.push(("target_os", Some(os)));
        ret.push(("target_family", Some(family)));
        ret.push(("target_arch", Some(arch)));
        // skip endianness
        ret.push(("target_pointer_width", Some(target_pointer_width)));
        ret.push(("target_env", Some(env)));

        return ret
    }
}

fn main() {
    // Prep the test generator
    let target = t!(env::var("TARGET"));
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let rust_out = BufWriter::new(t!(File::create(out.join("all.rs"))));
    let c_out = BufWriter::new(t!(File::create(out.join("all.c"))));
    let sess = ParseSess::new();
    let mut tg = TestGenerator {
        target: target,
        rust: Box::new(rust_out),
        c: Box::new(c_out),
        sh: &sess.span_diagnostic,
        structs: HashSet::new(),
    };

    // Parse the libc crate
    let src = Path::new("../src/lib.rs");
    let cfg = Vec::new();
    let mut krate = parse::parse_crate_from_file(src, cfg, &sess);

    // Strip the crate down to just what's configured for our target
    for (k, v) in tg.cfg_list() {
        let s = InternedString::new;
        krate.config.push(match v {
            Some(v) => attr::mk_name_value_item_str(s(k), s(v)),
            None => attr::mk_word_item(s(k)),
        });
    }
    let mut gated_cfgs = Vec::new();
    let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
                                                         krate,
                                                         &mut gated_cfgs);

    // Probe the crate to find all structs (used to convert type names to names
    // in C).
    let mut structs = StructFinder {
        structs: HashSet::new(),
    };
    visit::walk_crate(&mut structs, &krate);
    tg.structs = structs.structs;

    // Prep the C file by emitting header stuff
    for define in tg.defines() {
        t!(writeln!(tg.c, "#define {}", define));
    }
    for header in tg.headers() {
        t!(writeln!(tg.c, "#include <{}>", header));
    }

    // Walk the crate, emitting test cases for everything found
    visit::walk_crate(&mut tg, &krate);

    // Compile our C shim to be linked into tests
    let mut cfg = gcc::Config::new();
    cfg.file(out.join("all.c"));

    if tg.target.contains("msvc") {
        cfg.flag("/W3").flag("/Wall").flag("/WX");
    } else {
        cfg.flag("-Wall").flag("-Wextra").flag("-Werror")
           .arg("-Wno-unused-parameter");
    }

    drop(tg);
    cfg.compile("liball.a");
}

impl<'a> TestGenerator<'a> {
    fn test_type(&mut self, ty: &str) {
        match ty {
            "sighandler_t" => return,
            _ => {}
        }
        let c = self.rust2c(ty);
        self.test_size_align(ty, &c);
    }

    fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
        let cty = self.rust2c(ty);
        self.test_size_align(ty, &cty);

        t!(writeln!(self.rust, r#"
            #[test]
            fn field_offset_size_{ty}() {{
        "#, ty = ty));
        for field in s.fields.iter() {
            let name = match field.node.kind {
                ast::NamedField(name, ast::Public) => name,
                ast::NamedField(_, ast::Inherited) => continue,
                ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
            };

            let cfield = self.rust2cfield(ty, &name.to_string());

            t!(writeln!(self.c, r#"
                uint64_t __test_offset_{ty}_{rust_field}(void) {{
                    return offsetof({cty}, {c_field});
                }}
                uint64_t __test_size_{ty}_{rust_field}(void) {{
                    {cty}* foo = NULL;
                    return sizeof(foo->{c_field});
                }}
            "#, ty = ty, cty = cty, rust_field = name, c_field = cfield));
            t!(writeln!(self.rust, r#"
                extern {{
                    fn __test_offset_{ty}_{field}() -> u64;
                    fn __test_size_{ty}_{field}() -> u64;
                }}
                unsafe {{
                    let foo = 0 as *const {ty};
                    same(offset_of!({ty}, {field}),
                         __test_offset_{ty}_{field}(),
                         "field offset {field} of {ty}");
                    same(mem::size_of_val(&(*foo).{field}) as u64,
                         __test_size_{ty}_{field}(),
                         "field size {field} of {ty}");
                }}
            "#, ty = ty, field = name));
        }
        t!(writeln!(self.rust, r#"
            }}
        "#));
    }

    fn test_size_align(&mut self, rust: &str, c: &str) {
        t!(writeln!(self.c, r#"
            uint64_t __test_size_{ty}(void) {{ return sizeof({cty}); }}
            uint64_t __test_align_{ty}(void) {{ return alignof({cty}); }}
        "#, ty = rust, cty = c));
        t!(writeln!(self.rust, r#"
            #[test]
            fn size_align_{ty}() {{
                extern {{
                    fn __test_size_{ty}() -> u64;
                    fn __test_align_{ty}() -> u64;
                }}
                unsafe {{
                    same(mem::size_of::<{ty}>() as u64,
                         __test_size_{ty}(), "size");
                    same(align::<{ty}>() as u64,
                         __test_align_{ty}(), "align");
                }}
            }}
        "#, ty = rust));
    }

    fn test_const(&mut self, name: &str, rust_ty: &str) {
        let cty = self.rust2c(&rust_ty.replace("*mut ", "")
                                      .replace("*const ", ""));
        let ptrs = rust_ty.matches("*").count();
        let cty = format!("{}{}", cty,
                          iter::repeat("*").take(ptrs).collect::<String>());
        let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
        t!(writeln!(self.c, r#"
            int __test_const_{name}({cty} *out) {{
                int ret = 0;
                #if defined({name})
                    *out = {cast}({name});
                    ret = 1;
                #endif
                return ret;
            }}
        "#, name = name, cast = cast, cty = cty));
        t!(writeln!(self.rust, r#"
            #[test]
            fn const_{name}() {{
                extern {{
                    fn __test_const_{name}(out: *mut {ty}) -> c_int;
                }}
                unsafe {{
                    let mut o = mem::zeroed();
                    if __test_const_{name}(&mut o) == 0 {{
                        panic!("not defined");
                    }} else {{
                        same({name}, o, "value");
                    }}
                }}
            }}
        "#, ty = rust_ty, name = name));
    }

    fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
         assert!(generics.lifetimes.len() == 0);
         assert!(generics.ty_params.len() == 0);
         assert!(generics.where_clause.predicates.len() == 0);
    }

    fn ty2name(&self, ty: &ast::Ty) -> String {
        match ty.node {
            ast::TyPath(_, ref path) => {
                path.segments.last().unwrap().identifier.to_string()
            }
            ast::TyPtr(ref t) => {
                format!("*{} {}", match t.mutbl {
                    ast::MutImmutable => "const",
                    ast::MutMutable => "mut",
                }, self.ty2name(&t.ty))
            }
            _ => panic!("unknown ty {:?}", ty),
        }
    }
}

impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemTy(_, ref generics) => {
                 self.assert_no_generics(i, generics);
                 self.test_type(&i.ident.to_string());
             }

             ast::ItemStruct(ref s, ref generics) => {
                 self.assert_no_generics(i, generics);
                 let is_c = i.attrs.iter().any(|a| {
                    attr::find_repr_attrs(self.sh, a).iter().any(|a| {
                        *a == ReprAttr::ReprExtern
                    })
                 });
                 if !is_c {
                     panic!("{} is not marked #[repr(C)]", i.ident);
                 }
                 self.test_struct(&i.ident.to_string(), s);
             }

             ast::ItemConst(ref ty, _) => {
                 let ty = self.ty2name(ty);
                 self.test_const(&i.ident.to_string(), &ty);
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}

impl<'v> Visitor<'v> for StructFinder {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemStruct(..) => {
                 self.structs.insert(i.ident.to_string());
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}
<|endoftext|>


<commit_before>use std::{iter, mem};
use byteorder::{LE, ByteOrder};
use std::marker::PhantomData;

use crate::{accessor, buffer};

fn buffer_view_slice<'a, 's>(
    view: buffer::View<'a>,
    get_buffer_data: &dyn Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
) -> Option<&'s [u8]> {
    let start = view.offset();
    let end = start + view.length();
    get_buffer_data(view.buffer())
        .map(|slice| &slice[start..end])
}

/// General iterator for an accessor.
#[derive(Clone, Debug)]
pub enum Iter<'a, T: Item> {
    /// Standard accessor iterator.
    Standard(ItemIter<'a, T>),

    /// Iterator for accessor with sparse values.
    Sparse(SparseIter<'a, T>),
}

impl<'a, T: Item> Iterator for Iter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut Iter::Standard(ref mut iter) => iter.next(),
            &mut Iter::Sparse(ref mut iter) => iter.next(),
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for Iter<'a, T> {
    fn len(&self) -> usize {
        match self {
            &Iter::Standard(ref iter) => iter.len(),
            &Iter::Sparse(ref iter) => iter.values.len(),
        }
    }
}

/// Iterator over indices of sparse accessor.
#[derive(Clone, Debug)]
pub enum SparseIndicesIter<'a> {
    /// 8-bit indices.
    U8(ItemIter<'a, u8>),
    /// 16-bit indices.
    U16(ItemIter<'a, u16>),
    /// 32-bit indices.
    U32(ItemIter<'a, u32>),
}

impl<'a> Iterator for SparseIndicesIter<'a> {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            SparseIndicesIter::U8(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U16(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U32(ref mut iter) => iter.next(),
        }
    }
}

/// Iterates over a sparse accessor.
#[derive(Clone, Debug)]
pub struct SparseIter<'a, T: Item> {
    /// Base value iterator.
    ///
    /// This can be `None` if the base buffer view is not set. In this case the base values are all zero.
    base: Option<ItemIter<'a, T>>,

    /// Sparse indices iterator.
    indices: iter::Peekable<SparseIndicesIter<'a>>,

    /// Sparse values iterator.
    values: ItemIter<'a, T>,

    /// Iterator counter.
    counter: u32,
}

impl<'a, T: Item> SparseIter<'a, T> {
    /// Constructor.
    ///
    /// Here `base` is allowed to be `None` when the base buffer view is not explicitly specified.
    pub fn new(
        base: Option<ItemIter<'a, T>>,
        indices: SparseIndicesIter<'a>,
        values: ItemIter<'a, T>,
    ) -> Self {
        SparseIter {
            base,
            indices: indices.peekable(),
            values: values,
            counter: 0,
        }
    }
}

impl<'a, T: Item> Iterator for SparseIter<'a, T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let next_base_value = self.base.as_mut().map(|iter| iter.next()).unwrap_or(Some(T::zero()));
        if next_base_value.is_none() {
            return None;
        }

        let mut next_value = next_base_value.unwrap();
        let next_sparse_index = self.indices.peek().clone();
        if let Some(index) = next_sparse_index {
            if *index == self.counter {
                self.indices.next(); // advance
                next_value = self.values.next().unwrap();
            }
        }

        self.counter += 1;

        Some(next_value)
    }
}

/// Represents items that can be read by an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
pub trait Item {
    /// Create an object of this type from a byte slice.
    fn from_slice(slice: &[u8]) -> Self;
    /// Create an object of this type that represents a zero value.
    fn zero() -> Self;
}

/// Visits the items in an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
#[derive(Copy, Clone, Debug)]
pub struct ItemIter<'a, T: Item> {
    stride: usize,
    data: &'a [u8],
    _phantom: PhantomData<T>,
}

impl Item for i8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0] as i8
    }
    fn zero() -> Self {
        0
    }
}

impl Item for i16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_i16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0]
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u32(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for f32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_f32(slice)
    }
    fn zero() -> Self {
        0.0
    }
}

impl<T: Item + Copy> Item for [T; 2] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 2 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 2]
    }
}

impl<T: Item + Copy> Item for [T; 3] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 3 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[1 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[2 * mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 3]
    }
}

impl<T: Item + Copy> Item for [T; 4] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 4 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[1 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[2 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[3 * mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 4]
    }
}

impl<'a, T: Item> ItemIter<'a, T> {
    /// Constructor.
    pub fn new(slice: &'a [u8], stride: usize) -> Self {
        ItemIter {
            data: slice,
            stride: stride,
            _phantom: PhantomData,
        }
    }
}

impl<'a, 's, T: Item> Iter<'s, T> {
    /// Constructor.
    pub fn new<F>(
        accessor: super::Accessor<'a>,
        get_buffer_data: F,
    ) -> Option<Iter<'s, T>>
        where F: Clone + Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
    {
        let is_sparse = accessor.sparse().is_some();
        if is_sparse {
            let sparse = accessor.sparse();
            let indices = sparse.as_ref().unwrap().indices();
            let values = sparse.as_ref().unwrap().values();
            let base_iter = {
                // Using `if let` here instead of map to preserve the early return behavior.
                if let Some(view) = accessor.view() {
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());
                    let start = accessor.offset();
                    let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                    let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                        &slice[start..end]
                    } else {
                        return None
                    };
                    Some(ItemIter::new(subslice, stride))
                } else {
                    None
                }
            };
            let sparse_count = sparse.as_ref().unwrap().count() as usize;
            let index_iter = {
                let view = indices.view();
                let index_size = indices.index_type().size();
                let stride = view.stride().unwrap_or(index_size);
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = indices.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + index_size;
                    &slice[start..end]
                } else {
                    return None
                };
                match indices.index_type() {
                    accessor::sparse::IndexType::U8 => SparseIndicesIter::U8(ItemIter::new(subslice, stride)),
                    accessor::sparse::IndexType::U16 => SparseIndicesIter::U16(ItemIter::new(subslice, stride)),
                    accessor::sparse::IndexType::U32 => SparseIndicesIter::U32(ItemIter::new(subslice, stride)),
                }
            };
            let value_iter = {
                let view = values.view();
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = values.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + mem::size_of::<T>();
                    &slice[start..end]
                } else {
                    return None
                };
                ItemIter::new(subslice, stride)
            };
            Some(Iter::Sparse(SparseIter::new(base_iter, index_iter, value_iter)))
        } else {
            debug_assert_eq!(mem::size_of::<T>(), accessor.size());
            debug_assert!(mem::size_of::<T>() > 0);
            if let Some(view) = accessor.view() {
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                debug_assert!(stride >= mem::size_of::<T>(), "Mismatch in stride, expected at least {} stride but found {}", mem::size_of::<T>(), stride);
                let start = accessor.offset();
                let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    &slice[start..end]
                } else {
                    return None
                };
                Some(Iter::Standard(ItemIter { stride, data: subslice, _phantom: PhantomData }))
            } else {
                None
            }
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for ItemIter<'a, T> {}
impl<'a, T: Item> Iterator for ItemIter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let stride = if self.data.len() >= self.stride {
            Some(self.stride)
        } else if self.data.len() >= mem::size_of::<T>() {
            Some(mem::size_of::<T>())
        } else {
            None
        };
        if let Some(stride) = stride {
            let (val, data) = self.data.split_at(stride);
            let val = T::from_slice(val);
            self.data = data;
            Some(val)
        } else {
            None
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        if let Some(val_data) = self.data.get(nth * self.stride ..) {
            if val_data.len() >= mem::size_of::<T>() {
                let val = T::from_slice(val_data);
                self.data = &val_data[self.stride.min(val_data.len()) ..];
                Some(val)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> {
        if self.data.len() >= mem::size_of::<T>() {
            self.data
                .get((self.data.len() - 1) / self.stride * self.stride ..)
                .map(T::from_slice)
        } else {
            None
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.data.len() / self.stride
            + (self.data.len() % self.stride >= mem::size_of::<T>()) as usize;
        (hint, Some(hint))
    }
}
<commit_msg>Implement ExactSizeIterator for SparseIter<commit_after>use std::{iter, mem};
use byteorder::{LE, ByteOrder};
use std::marker::PhantomData;

use crate::{accessor, buffer};

fn buffer_view_slice<'a, 's>(
    view: buffer::View<'a>,
    get_buffer_data: &dyn Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
) -> Option<&'s [u8]> {
    let start = view.offset();
    let end = start + view.length();
    get_buffer_data(view.buffer())
        .map(|slice| &slice[start..end])
}

/// General iterator for an accessor.
#[derive(Clone, Debug)]
pub enum Iter<'a, T: Item> {
    /// Standard accessor iterator.
    Standard(ItemIter<'a, T>),

    /// Iterator for accessor with sparse values.
    Sparse(SparseIter<'a, T>),
}

impl<'a, T: Item> Iterator for Iter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut Iter::Standard(ref mut iter) => iter.next(),
            &mut Iter::Sparse(ref mut iter) => iter.next(),
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        match self {
            &mut Iter::Standard(ref mut iter) => iter.nth(nth),
            &mut Iter::Sparse(ref mut iter) => iter.nth(nth),
        }
    }

    fn last(self) -> Option<Self::Item> {
        match self {
            Iter::Standard(iter) => iter.last(),
            Iter::Sparse(iter) => iter.last(),
        }
    }

    fn count(self) -> usize {
        match self {
            Iter::Standard(iter) => iter.count(),
            Iter::Sparse(iter) => iter.count(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            &Iter::Standard(ref iter) => iter.size_hint(),
            &Iter::Sparse(ref iter) => iter.size_hint(),
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for Iter<'a, T> {}

/// Iterator over indices of sparse accessor.
#[derive(Clone, Debug)]
pub enum SparseIndicesIter<'a> {
    /// 8-bit indices.
    U8(ItemIter<'a, u8>),
    /// 16-bit indices.
    U16(ItemIter<'a, u16>),
    /// 32-bit indices.
    U32(ItemIter<'a, u32>),
}

impl<'a> Iterator for SparseIndicesIter<'a> {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            SparseIndicesIter::U8(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U16(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U32(ref mut iter) => iter.next(),
        }
    }
}

/// Iterates over a sparse accessor.
#[derive(Clone, Debug)]
pub struct SparseIter<'a, T: Item> {
    /// Base value iterator.
    ///
    /// This can be `None` if the base buffer view is not set. In this case the base values are all zero.
    base: Option<ItemIter<'a, T>>,

    /// Sparse indices iterator.
    indices: iter::Peekable<SparseIndicesIter<'a>>,

    /// Sparse values iterator.
    values: ItemIter<'a, T>,

    /// Iterator counter.
    counter: u32,
}

impl<'a, T: Item> SparseIter<'a, T> {
    /// Constructor.
    ///
    /// Here `base` is allowed to be `None` when the base buffer view is not explicitly specified.
    pub fn new(
        base: Option<ItemIter<'a, T>>,
        indices: SparseIndicesIter<'a>,
        values: ItemIter<'a, T>,
    ) -> Self {
        SparseIter {
            base,
            indices: indices.peekable(),
            values: values,
            counter: 0,
        }
    }
}

impl<'a, T: Item> Iterator for SparseIter<'a, T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let next_base_value = self.base.as_mut().map(|iter| iter.next()).unwrap_or(Some(T::zero()));
        if next_base_value.is_none() {
            return None;
        }

        let mut next_value = next_base_value.unwrap();
        let next_sparse_index = self.indices.peek().clone();
        if let Some(index) = next_sparse_index {
            if *index == self.counter {
                self.indices.next(); // advance
                next_value = self.values.next().unwrap();
            }
        }

        self.counter += 1;

        Some(next_value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.values.len() - self.counter as usize;
        (hint, Some(hint))
    }
}

impl<'a, T: Item> ExactSizeIterator for SparseIter<'a, T> {}

/// Represents items that can be read by an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
pub trait Item {
    /// Create an object of this type from a byte slice.
    fn from_slice(slice: &[u8]) -> Self;
    /// Create an object of this type that represents a zero value.
    fn zero() -> Self;
}

/// Visits the items in an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
#[derive(Copy, Clone, Debug)]
pub struct ItemIter<'a, T: Item> {
    stride: usize,
    data: &'a [u8],
    _phantom: PhantomData<T>,
}

impl Item for i8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0] as i8
    }
    fn zero() -> Self {
        0
    }
}

impl Item for i16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_i16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0]
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u32(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for f32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_f32(slice)
    }
    fn zero() -> Self {
        0.0
    }
}

impl<T: Item + Copy> Item for [T; 2] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 2 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 2]
    }
}

impl<T: Item + Copy> Item for [T; 3] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 3 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[1 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[2 * mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 3]
    }
}

impl<T: Item + Copy> Item for [T; 4] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 4 * mem::size_of::<T>());
        [T::from_slice(slice),
         T::from_slice(&slice[1 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[2 * mem::size_of::<T>() ..]),
         T::from_slice(&slice[3 * mem::size_of::<T>() ..])]
    }
    fn zero() -> Self {
        [T::zero(); 4]
    }
}

impl<'a, T: Item> ItemIter<'a, T> {
    /// Constructor.
    pub fn new(slice: &'a [u8], stride: usize) -> Self {
        ItemIter {
            data: slice,
            stride: stride,
            _phantom: PhantomData,
        }
    }
}

impl<'a, 's, T: Item> Iter<'s, T> {
    /// Constructor.
    pub fn new<F>(
        accessor: super::Accessor<'a>,
        get_buffer_data: F,
    ) -> Option<Iter<'s, T>>
        where F: Clone + Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
    {
        let is_sparse = accessor.sparse().is_some();
        if is_sparse {
            let sparse = accessor.sparse();
            let indices = sparse.as_ref().unwrap().indices();
            let values = sparse.as_ref().unwrap().values();
            let base_iter = {
                // Using `if let` here instead of map to preserve the early return behavior.
                if let Some(view) = accessor.view() {
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());
                    let start = accessor.offset();
                    let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                    let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                        &slice[start..end]
                    } else {
                        return None
                    };
                    Some(ItemIter::new(subslice, stride))
                } else {
                    None
                }
            };
            let sparse_count = sparse.as_ref().unwrap().count() as usize;
            let index_iter = {
                let view = indices.view();
                let index_size = indices.index_type().size();
                let stride = view.stride().unwrap_or(index_size);
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = indices.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + index_size;
                    &slice[start..end]
                } else {
                    return None
                };
                match indices.index_type() {
                    accessor::sparse::IndexType::U8 => SparseIndicesIter::U8(ItemIter::new(subslice, stride)),
                    accessor::sparse::IndexType::U16 => SparseIndicesIter::U16(ItemIter::new(subslice, stride)),
                    accessor::sparse::IndexType::U32 => SparseIndicesIter::U32(ItemIter::new(subslice, stride)),
                }
            };
            let value_iter = {
                let view = values.view();
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = values.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + mem::size_of::<T>();
                    &slice[start..end]
                } else {
                    return None
                };
                ItemIter::new(subslice, stride)
            };
            Some(Iter::Sparse(SparseIter::new(base_iter, index_iter, value_iter)))
        } else {
            debug_assert_eq!(mem::size_of::<T>(), accessor.size());
            debug_assert!(mem::size_of::<T>() > 0);
            if let Some(view) = accessor.view() {
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                debug_assert!(stride >= mem::size_of::<T>(), "Mismatch in stride, expected at least {} stride but found {}", mem::size_of::<T>(), stride);
                let start = accessor.offset();
                let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    &slice[start..end]
                } else {
                    return None
                };
                Some(Iter::Standard(ItemIter { stride, data: subslice, _phantom: PhantomData }))
            } else {
                None
            }
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for ItemIter<'a, T> {}
impl<'a, T: Item> Iterator for ItemIter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let stride = if self.data.len() >= self.stride {
            Some(self.stride)
        } else if self.data.len() >= mem::size_of::<T>() {
            Some(mem::size_of::<T>())
        } else {
            None
        };
        if let Some(stride) = stride {
            let (val, data) = self.data.split_at(stride);
            let val = T::from_slice(val);
            self.data = data;
            Some(val)
        } else {
            None
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        if let Some(val_data) = self.data.get(nth * self.stride ..) {
            if val_data.len() >= mem::size_of::<T>() {
                let val = T::from_slice(val_data);
                self.data = &val_data[self.stride.min(val_data.len()) ..];
                Some(val)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> {
        if self.data.len() >= mem::size_of::<T>() {
            self.data
                .get((self.data.len() - 1) / self.stride * self.stride ..)
                .map(T::from_slice)
        } else {
            None
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.data.len() / self.stride
            + (self.data.len() % self.stride >= mem::size_of::<T>()) as usize;
        (hint, Some(hint))
    }
}
<|endoftext|>


<commit_before>//! `IoHandler` middlewares

use crate::calls::Metadata;
use crate::types::{Request, Response, Call, Output};
use futures::{future::Either, Future};

/// RPC middleware
pub trait Middleware<M: Metadata>: Send + Sync + 'static {
	/// A returned request future.
	type Future: Future<Item=Option<Response>, Error=()> + Send + 'static;

	/// A returned call future.
	type CallFuture: Future<Item=Option<Output>, Error=()> + Send + 'static;

	/// Method invoked on each request.
	/// Allows you to either respond directly (without executing RPC call)
	/// or do any additional work before and/or after processing the request.
	fn on_request<F, X>(&self, request: Request, meta: M, next: F) -> Either<Self::Future, X> where
		F: FnOnce(Request, M) -> X + Send,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		Either::B(next(request, meta))
	}

	/// Method invoked on each call inside a request.
	///
	/// Allows you to either handle the call directly (without executing RPC call).
	fn on_call<F, X>(&self, call: Call, meta: M, next: F) -> Either<Self::CallFuture, X> where
		F: FnOnce(Call, M) -> X + Send,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		Either::B(next(call, meta))
	}
}

/// Dummy future used as a noop result of middleware.
pub type NoopFuture = Box<Future<Item=Option<Response>, Error=()> + Send>;
/// Dummy future used as a noop call result of middleware.
pub type NoopCallFuture = Box<Future<Item=Option<Output>, Error=()> + Send>;

/// No-op middleware implementation
#[derive(Debug, Default)]
pub struct Noop;
impl<M: Metadata> Middleware<M> for Noop {
	type Future = NoopFuture;
	type CallFuture = NoopCallFuture;
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>>
	Middleware<M> for (A, B)
{
	type Future = Either<A::Future, B::Future>;
	type CallFuture = Either<A::CallFuture, B::CallFuture>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: FnOnce(Request, M) -> X + Send,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, move |request, meta| {
			self.1.on_request(request, meta, process)
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: FnOnce(Call, M) -> X + Send,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, move |call, meta| {
			self.1.on_call(call, meta, process)
		}))
	}
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>, C: Middleware<M>>
	Middleware<M> for (A, B, C)
{
	type Future = Either<A::Future, Either<B::Future, C::Future>>;
	type CallFuture = Either<A::CallFuture, Either<B::CallFuture, C::CallFuture>>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: FnOnce(Request, M) -> X + Send,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, move |request, meta| {
			repack(self.1.on_request(request, meta, move |request, meta| {
				self.2.on_request(request, meta, process)
			}))
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: FnOnce(Call, M) -> X + Send,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, move |call, meta| {
			repack(self.1.on_call(call, meta, move |call, meta| {
				self.2.on_call(call, meta, process)
			}))
		}))
	}
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>, C: Middleware<M>, D: Middleware<M>>
	Middleware<M> for (A, B, C, D)
{
	type Future = Either<A::Future, Either<B::Future, Either<C::Future, D::Future>>>;
	type CallFuture = Either<A::CallFuture, Either<B::CallFuture, Either<C::CallFuture, D::CallFuture>>>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: FnOnce(Request, M) -> X + Send,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, move |request, meta| {
			repack(self.1.on_request(request, meta, move |request, meta| {
				repack(self.2.on_request(request, meta, move |request, meta| {
					self.3.on_request(request, meta, process)
				}))
			}))
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: FnOnce(Call, M) -> X + Send,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, move |call, meta| {
			repack(self.1.on_call(call, meta, move |call, meta| {
				repack(self.2.on_call(call, meta, move |call, meta| {
					self.3.on_call(call, meta, process)
				}))
			}))
		}))
	}
}

#[inline(always)]
fn repack<A, B, X>(result: Either<A, Either<B, X>>) -> Either<Either<A, B>, X> {
	match result {
		Either::A(a) => Either::A(Either::A(a)),
		Either::B(Either::A(b)) => Either::A(Either::B(b)),
		Either::B(Either::B(x)) => Either::B(x),
	}
}
<commit_msg>Use less restrictive signature for Middleware trait's `next` (#391)<commit_after>//! `IoHandler` middlewares

use crate::calls::Metadata;
use crate::types::{Request, Response, Call, Output};
use futures::{future::Either, Future};

/// RPC middleware
pub trait Middleware<M: Metadata>: Send + Sync + 'static {
	/// A returned request future.
	type Future: Future<Item=Option<Response>, Error=()> + Send + 'static;

	/// A returned call future.
	type CallFuture: Future<Item=Option<Output>, Error=()> + Send + 'static;

	/// Method invoked on each request.
	/// Allows you to either respond directly (without executing RPC call)
	/// or do any additional work before and/or after processing the request.
	fn on_request<F, X>(&self, request: Request, meta: M, next: F) -> Either<Self::Future, X> where
		F: Fn(Request, M) -> X + Send + Sync,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		Either::B(next(request, meta))
	}

	/// Method invoked on each call inside a request.
	///
	/// Allows you to either handle the call directly (without executing RPC call).
	fn on_call<F, X>(&self, call: Call, meta: M, next: F) -> Either<Self::CallFuture, X> where
		F: Fn(Call, M) -> X + Send + Sync,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		Either::B(next(call, meta))
	}
}

/// Dummy future used as a noop result of middleware.
pub type NoopFuture = Box<Future<Item=Option<Response>, Error=()> + Send>;
/// Dummy future used as a noop call result of middleware.
pub type NoopCallFuture = Box<Future<Item=Option<Output>, Error=()> + Send>;

/// No-op middleware implementation
#[derive(Debug, Default)]
pub struct Noop;
impl<M: Metadata> Middleware<M> for Noop {
	type Future = NoopFuture;
	type CallFuture = NoopCallFuture;
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>>
	Middleware<M> for (A, B)
{
	type Future = Either<A::Future, B::Future>;
	type CallFuture = Either<A::CallFuture, B::CallFuture>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: Fn(Request, M) -> X + Send + Sync,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, |request, meta| {
			self.1.on_request(request, meta, &process)
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: Fn(Call, M) -> X + Send + Sync,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, |call, meta| {
			self.1.on_call(call, meta, &process)
		}))
	}
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>, C: Middleware<M>>
	Middleware<M> for (A, B, C)
{
	type Future = Either<A::Future, Either<B::Future, C::Future>>;
	type CallFuture = Either<A::CallFuture, Either<B::CallFuture, C::CallFuture>>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: Fn(Request, M) -> X + Send + Sync,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, |request, meta| {
			repack(self.1.on_request(request, meta, |request, meta| {
				self.2.on_request(request, meta, &process)
			}))
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: Fn(Call, M) -> X + Send + Sync,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, |call, meta| {
			repack(self.1.on_call(call, meta, |call, meta| {
				self.2.on_call(call, meta, &process)
			}))
		}))
	}
}

impl<M: Metadata, A: Middleware<M>, B: Middleware<M>, C: Middleware<M>, D: Middleware<M>>
	Middleware<M> for (A, B, C, D)
{
	type Future = Either<A::Future, Either<B::Future, Either<C::Future, D::Future>>>;
	type CallFuture = Either<A::CallFuture, Either<B::CallFuture, Either<C::CallFuture, D::CallFuture>>>;

	fn on_request<F, X>(&self, request: Request, meta: M, process: F) -> Either<Self::Future, X> where
		F: Fn(Request, M) -> X + Send + Sync,
		X: Future<Item=Option<Response>, Error=()> + Send + 'static,
	{
		repack(self.0.on_request(request, meta, |request, meta| {
			repack(self.1.on_request(request, meta, |request, meta| {
				repack(self.2.on_request(request, meta, |request, meta| {
					self.3.on_request(request, meta, &process)
				}))
			}))
		}))
	}

	fn on_call<F, X>(&self, call: Call, meta: M, process: F) -> Either<Self::CallFuture, X> where
		F: Fn(Call, M) -> X + Send + Sync,
		X: Future<Item=Option<Output>, Error=()> + Send + 'static,
	{
		repack(self.0.on_call(call, meta, |call, meta| {
			repack(self.1.on_call(call, meta, |call, meta| {
				repack(self.2.on_call(call, meta, |call, meta| {
					self.3.on_call(call, meta, &process)
				}))
			}))
		}))
	}
}

#[inline(always)]
fn repack<A, B, X>(result: Either<A, Either<B, X>>) -> Either<Either<A, B>, X> {
	match result {
		Either::A(a) => Either::A(Either::A(a)),
		Either::B(Either::A(b)) => Either::A(Either::B(b)),
		Either::B(Either::B(x)) => Either::B(x),
	}
}
<|endoftext|>