// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

use crate::{Error, Result};
use bitflags::bitflags;
use optee_utee_sys as raw;
use std::{marker, mem, ptr};

/// A general attribute (buffer or value) that can be used to populate an object or to specify
/// opeation parameters.
pub struct Attribute {
    raw: raw::TEE_Attribute,
}

impl Attribute {
    /// Return the raw struct `TEE_Attribute`.
    pub fn raw(&self) -> raw::TEE_Attribute {
        self.raw
    }
}

/// Convert the buffer attribute [AttributeMemref](AttributeMemref) to the general attribute.
impl<'attrref> From<AttributeMemref<'attrref>> for Attribute {
    fn from(attr: AttributeMemref) -> Self {
        Self { raw: attr.raw() }
    }
}

/// Convert the value attribute [AttributeValue](AttributeValue) to the general attribute.
impl From<AttributeValue> for Attribute {
    fn from(attr: AttributeValue) -> Self {
        Self { raw: attr.raw() }
    }
}

/// A buffer attribute.
#[derive(Clone, Copy)]
pub struct AttributeMemref<'attrref> {
    raw: raw::TEE_Attribute,
    _marker: marker::PhantomData<&'attrref mut [u8]>,
}

impl<'attrref> AttributeMemref<'attrref> {
    /// Return the raw struct TEE_Attribute.
    pub fn raw(&self) -> raw::TEE_Attribute {
        self.raw
    }

    fn new_ref() -> Self {
        let raw = raw::TEE_Attribute {
            attributeID: 0,
            content: raw::content {
                memref: raw::Memref {
                    buffer: 0 as *mut _,
                    size: 0,
                },
            },
        };
        Self {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }

    /// Populate a single attribute with a reference to a buffer.
    ///
    /// # Parameters
    ///
    /// 1) `id`: The AttributeId[AttributeId] is an identifier of the attribute to populate.
    /// 2) `buffer`: Input buffer that holds the content of the attribute.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let mut attr = AttributeMemref::from_ref(AttributeId::SecretValue, &mut [0u8;1]);
    /// ```
    pub fn from_ref(id: AttributeId, buffer: &'attrref [u8]) -> Self {
        let mut res = AttributeMemref::new_ref();
        unsafe {
            raw::TEE_InitRefAttribute(
                &mut res.raw,
                id as u32,
                buffer.as_ptr() as *mut _,
                buffer.len() as u32,
            );
        }
        res
    }
}

/// A value attribute.
pub struct AttributeValue {
    raw: raw::TEE_Attribute,
}

impl AttributeValue {
    /// Return the raw struct TEE_Attribute.
    pub fn raw(&self) -> raw::TEE_Attribute {
        self.raw
    }

    fn new_value() -> Self {
        let raw = raw::TEE_Attribute {
            attributeID: 0,
            content: raw::content {
                value: raw::Value { a: 0, b: 0 },
            },
        };
        Self { raw }
    }

    /// Populate a single attribute with two u32 values.
    ///
    /// # Parameters
    ///
    /// 1) `id`: The AttributeId[AttributeId] is an identifier of the attribute to populate.
    /// 2) `a`, `b`: u32 values to assign to the members of the a value attribute.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let mut attr = AttributeValue::from_value(AttributeId::SecretValue, 0, 0);
    /// ```
    pub fn from_value(id: AttributeId, a: u32, b: u32) -> Self {
        let mut res = AttributeValue::new_value();
        unsafe {
            raw::TEE_InitValueAttribute(&mut res.raw, id as u32, a, b);
        }
        res
    }
}

/// Represent the characteristics of an object.
/// This info can be returned by [TransientObject](TransientObject) function
/// [info](TransientObject::info)
/// or [PersistentObject](PersistentObject) function
/// [info](PersistentObject::info).
pub struct ObjectInfo {
    raw: raw::TEE_ObjectInfo,
}

// Since raw struct is not implemented Copy attribute yet, every item in raw struct needs a function to extract.
impl ObjectInfo {
    /// Return an [ObjectInfo](ObjectInfo) struct based on the raw structrure `TEE_ObjectInfo`.
    /// The raw structure contains following fields:
    ///
    /// 1) `objectType`: The parameter represents one of the
    ///    [TransientObjectType](TransientObjectType).
    /// 2) `objectSize`: The current size in bits of the object as determined by its attributes.
    /// This will always be less than or equal to maxObjectSize. Set to 0 for uninitialized and data only objects.
    /// 3) `maxObjectSize`: The maximum objectSize which this object can represent.
    /// 3.1) For a [PersistentObject](PersistentObject), set to `objectSize`.
    /// 3.2) For a [TransientObject](TransientObject), set to the parameter `maxObjectSize` passed to
    /// [allocate](TransientObject::allocate).
    /// 4) `objectUsage`: A bit vector of UsageFlag.
    /// 5) `dataSize`:
    /// 5.1) For a [PersistentObject](PersistentObject), set to the current size of the data associated with the object.
    /// 5.2) For a [TransientObject](TransientObject), always set to 0.
    /// 6) `dataPosition`:
    /// 6.1) For a [PersistentObject](PersistentObject), set to the current position in the data for this handle.
    /// Data positions for different handles on the same object may differ.
    /// 6.2) For a [TransientObject](TransientObject), set to 0.
    /// 7) `handleFlags`: A bit vector containing one or more [HandleFlag](HandleFlag) or [DataFlag](DataFlag).
    pub fn from_raw(raw: raw::TEE_ObjectInfo) -> Self {
        Self { raw }
    }

    /// Return the `dataSize` field of the raw structrure `TEE_ObjectInfo`.
    pub fn data_size(&self) -> usize {
        self.raw.dataSize as usize
    }

    /// Return the `objectSize` field of the raw structrure `TEE_ObjectInfo`.
    pub fn object_size(&self) -> usize {
        self.raw.objectSize as usize
    }
}

/// Indicate the possible start offset when moving a data position in the data stream associated with a [PersistentObject](PersistentObject).
pub enum Whence {
    /// The data position is set to offset bytes from the beginning of the data stream.
    DataSeekSet,
    /// The data position is set to its current position plus offset.
    DataSeekCur,
    /// The data position is set to the size of the object data plus offset.
    DataSeekEnd,
}

impl Into<raw::TEE_Whence> for Whence {
    fn into(self) -> raw::TEE_Whence {
        match self {
            Whence::DataSeekSet => raw::TEE_Whence::TEE_DATA_SEEK_SET,
            Whence::DataSeekCur => raw::TEE_Whence::TEE_DATA_SEEK_CUR,
            Whence::DataSeekEnd => raw::TEE_Whence::TEE_DATA_SEEK_END,
        }
    }
}

/// An opaque handle on an object.
pub struct ObjectHandle {
    raw: *mut raw::TEE_ObjectHandle,
}

impl ObjectHandle {
    fn handle(&self) -> raw::TEE_ObjectHandle {
        unsafe { *(self.raw) }
    }

    fn from_raw(raw: *mut raw::TEE_ObjectHandle) -> ObjectHandle {
        Self { raw }
    }

    fn info(&self) -> Result<ObjectInfo> {
        let mut raw_info: raw::TEE_ObjectInfo = unsafe { mem::zeroed() };
        match unsafe { raw::TEE_GetObjectInfo1(self.handle(), &mut raw_info) } {
            raw::TEE_SUCCESS => Ok(ObjectInfo::from_raw(raw_info)),
            code => Err(Error::from_raw_error(code)),
        }
    }

    fn restrict_usage(&mut self, obj_usage: UsageFlag) -> Result<()> {
        match unsafe { raw::TEE_RestrictObjectUsage1(self.handle(), obj_usage.bits()) } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }

    fn ref_attribute(&self, id: AttributeId, buffer: &mut [u8]) -> Result<usize> {
        let mut size = buffer.len() as u32;
        match unsafe {
            raw::TEE_GetObjectBufferAttribute(
                self.handle(),
                id as u32,
                buffer as *mut _ as _,
                &mut size as _,
            )
        } {
            raw::TEE_SUCCESS => Ok(size as usize),
            code => Err(Error::from_raw_error(code)),
        }
    }

    fn value_attribute(&self, id: u32) -> Result<(u32, u32)> {
        let mut value_a: u32 = 0;
        let mut value_b: u32 = 0;
        match unsafe {
            raw::TEE_GetObjectValueAttribute(
                self.handle(),
                id,
                &mut value_a as *mut _,
                &mut value_b as *mut _,
            )
        } {
            raw::TEE_SUCCESS => Ok((value_a, value_b)),
            code => Err(Error::from_raw_error(code)),
        }
    }
}

#[repr(u32)]
pub enum ObjectStorageConstants {
    Private = 0x00000001,
    IllegalValue = 0x7FFFFFFF,
}

bitflags! {
    /// A set of flags that controls the access rights and sharing permissions
    /// with which the object handle is opened.
    pub struct DataFlag: u32 {
        /// The object is opened with the read access right. This allows the
        /// Trusted Application to call the function `TEE_ReadObjectData`.
        const ACCESS_READ = 0x00000001;
        /// The object is opened with the write access right. This allows the
        /// Trusted Application to call the functions `TEE_WriteObjectData` and
        /// `TEE_TruncateObjectData`.
        const ACCESS_WRITE = 0x00000002;
        /// The object is opened with the write-meta access right. This allows
        /// the Trusted Application to call the functions
        /// `TEE_CloseAndDeletePersistentObject1` and `TEE_RenamePersistentObject`.
        const ACCESS_WRITE_META = 0x00000004;
        /// The caller allows another handle on the object to be created with
        /// read access.
        const SHARE_READ = 0x00000010;
        /// The caller allows another handle on the object to be created with
        /// write access.
        const SHARE_WRITE = 0x00000020;
        /// * If this flag is present and the object exists, then the object is
        ///   deleted and re-created as an atomic operation: that is, the TA sees
        ///   either the old object or the new one.
        /// * If the flag is absent and the object exists, then the function
        ///   SHALL return `TEE_ERROR_ACCESS_CONFLICT`.
        const OVERWRITE = 0x00000400;
    }
}

bitflags! {
    /// A set of flags that defines usages of data in TEE secure storage.
    pub struct UsageFlag: u32 {
        /// The object [Attribute](Attribute) can be extracted.
        const EXTRACTABLE = 0x00000001;
        /// The object can be used for encrytpion.
        const ENCRYPT = 0x00000002;
        /// The object can be used for decrption.
        const DECRYPT = 0x00000004;
        /// The object can be used for mac operation.
        const MAC = 0x00000008;
        /// The ojbect can be used for signature.
        const SIGN = 0x00000010;
        /// The object can be used for verification of a signature.
        const VERIFY = 0x00000020;
        /// The object can be used for deriving a key.
        const DERIVE = 0x00000040;
    }
}

/// Miscellaneous constants.
#[repr(u32)]
pub enum MiscellaneousConstants {
    /// Maximum offset of a data object.
    TeeDataMaxPosition = 0xFFFFFFFF,
    /// Maximum length of an object id.
    TeeObjectIdMaxLen = 64,
}

bitflags! {
    /// A set of flags that defines Handle features.
    pub struct HandleFlag: u32{
        /// Set for a [PersistentObject](PersistentObject).
        const PERSISTENT = 0x00010000;
        /// 1) For a [PersistentObject](PersistentObject), always set.
        /// 2) For a [TransientObject](TransientObject), initially cleared, then set when the object becomes initialized.
        const INITIALIZED = 0x00020000;
        /// Following two flags are for crypto operation handles:
        /// 1) Set if the required operation key has been set.
        /// 2) Always set for digest operations.
        const KEY_SET = 0x00040000;
        /// Set if the algorithm expects two keys to be set, using `TEE_SetOperationKey2`.
        /// This happens only if algorithm is set to [AesXts](../crypto_op/enum.AlgorithmId.html#variant.AesXts)
        /// or `TEE_ALG_SM2_KEP`(not supported now).
        const EXPECT_TWO_KEYS = 0x00080000;
    }
}

#[repr(u32)]
pub enum AttributeId {
    /// Used for all secret keys for symmetric ciphers, MACs, and HMACs
    SecretValue = 0xC0000000,
    /// RSA modulus: `n`
    RsaModulus = 0xD0000130,
    /// RSA public key exponent: `e`
    RsaPublicExponent = 0xD0000230,
    /// RSA private key exponent: `d`
    RsaPrivateExponent = 0xC0000330,
    /// RSA prime number: `p`
    RsaPrime1 = 0xC0000430,
    /// RSA prime number: `q`
    RsaPrime2 = 0xC0000530,
    /// RSA exponent: `dp`
    RsaExponent1 = 0xC0000630,
    /// RSA exponent: `dq`
    RsaExponent2 = 0xC0000730,
    /// RSA coefficient: `iq`
    RsaCoefficient = 0xC0000830,
    /// DSA prime number: `p`
    DsaPrime = 0xD0001031,
    /// DSA sub prime number: `q`
    DsaSubprime = 0xD0001131,
    /// DSA base: `g`
    DsaBase = 0xD0001231,
    /// DSA public value: `y`
    DsaPublicValue = 0xD0000131,
    /// DSA private value: `x`
    DsaPrivateValue = 0xC0000231,
    /// Diffie-Hellman prime number: `p`
    DhPrime = 0xD0001032,
    /// Diffie-Hellman sub prime number: `q`
    DhSubprime = 0xD0001132,
    /// Diffie-Hellman base: `g`
    DhBase = 0xD0001232,
    /// Diffie-Hellman x bits: `l`
    DhXBits = 0xF0001332,
    /// Diffie-Hellman public value: `y`
    DhPublicValue = 0xD0000132,
    /// Diffie-Hellman public value: `x`
    DhPrivateValue = 0xC0000232,
    RsaOaepLabel = 0xD0000930,
    RsaPssSaltLength = 0xF0000A30,
    EccPublicValueX = 0xD0000141,
    EccPublicValueY = 0xD0000241,
    /// ECC private value: `d`
    EccPrivateValue = 0xC0000341,
    /// ECC Curve algorithm
    EccCurve = 0xF0000441,
    BitProtected = (1 << 28),
    BitValue = (1 << 29),
}

/// Define types of [TransientObject](TransientObject) with predefined maximum sizes.
#[repr(u32)]
pub enum TransientObjectType {
    /// 128, 192, or 256 bits
    Aes = 0xA0000010,
    /// Always 64 bits including the parity bits. This gives an effective key size of 56 bits
    Des = 0xA0000011,
    /// 128 or 192 bits including the parity bits. This gives effective key sizes of 112 or 168 bits
    Des3 = 0xA0000013,
    /// Between 64 and 512 bits, multiple of 8 bits
    HmacMd5 = 0xA0000001,
    /// Between 80 and 512 bits, multiple of 8 bits
    HmacSha1 = 0xA0000002,
    /// Between 112 and 512 bits, multiple of 8 bits
    HmacSha224 = 0xA0000003,
    /// Between 192 and 1024 bits, multiple of 8 bits
    HmacSha256 = 0xA0000004,
    /// Between 256 and 1024 bits, multiple of 8 bits
    HmacSha384 = 0xA0000005,
    /// Between 256 and 1024 bits, multiple of 8 bits
    HmacSha512 = 0xA0000006,
    /// The number of bits in the modulus. 256, 512, 768, 1024, 1536 and 2048 bit keys SHALL be supported.
    /// Support for other key sizes including bigger key sizes is
    /// implementation-dependent. Minimum key size is 256 bits
    RsaPublicKey = 0xA0000030,
    /// Same as [RsaPublicKey](TransientObjectType::RsaPublicKey) key size.
    RsaKeypair = 0xA1000030,
    /// Depends on Algorithm:
    /// 1) [DsaSha1](../crypto_op/enum.AlgorithmId.html#variant.DsaSha1):
    /// Between 512 and 1024 bits, multiple of 64 bits
    /// 2) [DsaSha224](../crypto_op/enum.AlgorithmId.html#variant.DsaSha224): 2048 bits
    /// 3) [DsaSha256](../crypto_op/enum.AlgorithmId.html#variant.DsaSha256): 2048 or 3072 bits
    DsaPublicKey = 0xA0000031,
    /// Same as [DsaPublicKey](TransientObjectType::DsaPublicKey) key size.
    DsaKeypair = 0xA1000031,
    /// From 256 to 2048 bits, multiple of 8 bits.
    DhKeypair = 0xA1000032,
    /// Between 160 and 521 bits. Conditional: Available only if at least
    /// one of the ECC the curves defined in Table 6-14 with "generic"
    /// equal to "Y" is supported.
    EcdsaPublicKey = 0xA0000041,
    /// Between 160 and 521 bits. Conditional: Available only if at least
    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
    /// "Y" is supported. SHALL be same value as for ECDSA public key size.
    EcdsaKeypair = 0xA1000041,
    /// Between 160 and 521 bits. Conditional: Available only if at least
    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
    /// "Y" is supported.
    EcdhPublicKey = 0xA0000042,
    /// Between 160 and 521 bits. Conditional: Available only if at least
    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
    /// "Y" is supported. SHALL be same value as for ECDH public key size
    EcdhKeypair = 0xA1000042,
    /// Multiple of 8 bits, up to 4096 bits. This type is intended for secret
    /// data that has been derived from a key derivation scheme.
    GenericSecret = 0xA0000000,
    /// Object is corrupted.
    CorruptedObject = 0xA00000BE,
    /// 0 – All data is in the associated data stream.
    Data = 0xA00000BF,
}

/// A trait for an object (trasient or persistent) to return its handle.
pub trait ObjHandle {
    /// Return the handle of an object.
    fn handle(&self) -> raw::TEE_ObjectHandle;
}

/// An object containing attributes but no data stream, which is reclaimed
/// when closed or when the TA instance is destroyed.
/// Transient objects are used to hold a cryptographic object (key or key-pair).
///
/// Contrast [PersistentObject](PersistentObject).
pub struct TransientObject(ObjectHandle);

impl TransientObject {
    /// Create a [TransientObject](TransientObject) with a null handle which points to nothing.
    pub fn null_object() -> Self {
        Self(ObjectHandle::from_raw(ptr::null_mut()))
    }

    /// Allocate an uninitialized [TransientObject](TransientObject), i.e. a container for attributes.
    ///
    /// As allocated, the object is uninitialized.
    /// It can be initialized by subsequently importing the object material, generating an object,
    /// deriving an object, or loading an object from the Trusted Storage.
    ///
    /// # Parameters
    ///
    /// 1) `object_type`: Type of uninitialized object container to be created as defined in
    /// [TransientObjectType](TransientObjectType).
    /// 2) `max_object_size`: Key Size of the object. Valid values depend on the object type and are
    ///    defined in [TransientObjectType](TransientObjectType).
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) =>
    ///     {
    ///         // ...
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `OutOfMemory`: If not enough resources are available to allocate the object handle.
    /// 2) `NotSupported`: If the key size is not supported or the object type is not supported.
    ///
    /// # Panics
    ///
    /// 1) If the Implementation detects any error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn allocate(object_type: TransientObjectType, max_object_size: usize) -> Result<Self> {
        let raw_handle: *mut raw::TEE_ObjectHandle = Box::into_raw(Box::new(ptr::null_mut()));
        match unsafe {
            raw::TEE_AllocateTransientObject(object_type as u32, max_object_size as u32, raw_handle)
        } {
            raw::TEE_SUCCESS => {
                let handle = ObjectHandle::from_raw(raw_handle);
                Ok(Self(handle))
            }
            code => Err(Error::from_raw_error(code)),
        }
    }

    ///Reset a [TransientObject](TransientObject) to its initial state after allocation.
    ///If the object is currently initialized, the function clears the object of all its material.
    ///The object is then uninitialized again.
    pub fn reset(&mut self) {
        unsafe {
            raw::TEE_ResetTransientObject(self.handle());
        }
    }

    /// Populate an uninitialized object container with object attributes passed by the TA in the `attrs` parameter.
    /// When this function is called, the object SHALL be uninitialized.
    /// If the object is initialized, the caller SHALL first clear it using the function reset.
    /// Note that if the object type is a key-pair, then this function sets both the private and public attributes of the keypair.
    ///
    /// # Parameters
    ///
    /// 1) `attrs`: Array of object attributes.
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) =>
    ///     {
    ///         let attrs = [AttributeMemref::from_ref(AttributeId::SecretValue, &[0u8;1])];
    ///         object.populate(&attrs);
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `BadParameters`: If an incorrect or inconsistent attribute value is detected. In this case,
    /// the content of the object SHALL remain uninitialized.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object that is transient and uninitialized.
    /// 2) If some mandatory attribute is missing.
    /// 3) If an attribute which is not defined for the object’s type is present in attrs.
    /// 4) If an attribute value is too big to fit within the maximum object size specified when the object was created.
    /// 5) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn populate(&mut self, attrs: &[Attribute]) -> Result<()> {
        let p: Vec<raw::TEE_Attribute> = attrs.iter().map(|p| p.raw()).collect();
        match unsafe {
            raw::TEE_PopulateTransientObject(self.0.handle(), p.as_ptr() as _, attrs.len() as u32)
        } {
            raw::TEE_SUCCESS => Ok(()),
            code => return Err(Error::from_raw_error(code)),
        }
    }

    /// Return the characteristics of an object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) => {
    ///         match object.info() {
    ///             Ok(info) => {
    ///                 // ...
    ///                 Ok(())
    ///             }
    ///         Err(e) => Err(e),
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn info(&self) -> Result<ObjectInfo> {
        self.0.info()
    }

    /// Restrict the object usage flags of an object handle to contain at most the flags passed in the obj_usage parameter.
    ///
    /// The initial value of the key usage contains all usage flags.
    ///
    /// # Parameters
    ///
    /// 1) `obj_usage`: New object usage, an OR comination of one or more of the [UsageFlag](UsageFlag).
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) =>
    ///     {
    ///         object.restrict_usage(UsageFlag::ENCRYPT)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn restrict_usage(&mut self, obj_usage: UsageFlag) -> Result<()> {
        self.0.restrict_usage(obj_usage)
    }

    /// Extract one buffer attribute from an object. The attribute is identified by the argument id.
    ///
    /// # Parameters
    ///
    /// 1) `id`: Identifier of the attribute to retrieve.
    /// 2) `ref_attr`: Output buffer to get the content of the attribute.
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) => {
    ///         let mut attr = [0u8; 16];
    ///         match object.ref_attribute(id, &mut attr) {
    ///             Ok(size) => {
    ///                 // ...
    ///                 Ok(())
    ///             }
    ///             Err(e) => Err(e),
    ///         }
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `ItemNotFound`: If the attribute is not found on this object.
    /// 2) `ShortBuffer`: If buffer is NULL or too small to contain the key part.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the object is not initialized.
    /// 3) If the Attribute is not a buffer attribute.
    pub fn ref_attribute(&self, id: AttributeId, buffer: &mut [u8]) -> Result<usize> {
        self.0.ref_attribute(id, buffer)
    }

    /// Extract one value attribute from an object. The attribute is identified by the argument id.
    ///
    /// # Parameters
    ///
    /// 1) `id`: Identifier of the attribute to retrieve.
    /// 2) `value_attr`: Two value placeholders to get the content of the attribute.
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) => {
    ///         match object.value_attribute(id) {
    ///             Ok(a,b) => {
    ///                 // ...
    ///                 Ok(())
    ///             }
    ///             Err(e) => Err(e),
    ///         }
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `ItemNotFound`: If the attribute is not found on this object.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the object is not initialized.
    /// 3) If the Attribute is not a value attribute.
    pub fn value_attribute(&self, id: u32) -> Result<(u32, u32)> {
        self.0.value_attribute(id)
    }

    /// Populates an uninitialized object handle with the attributes of another object handle;
    /// that is, it populates the attributes of this handle with the attributes of src_handle.
    /// It is most useful in the following situations:
    /// 1) To extract the public key attributes from a key-pair object.
    /// 2) To copy the attributes from a [PersistentObject](PersistentObject) into a [TransientObject](TransientObject).
    ///
    /// # Parameters
    ///
    /// 1) `src_object`: Can be either a [TransientObject](TransientObject) or [PersistentObject](PersistentObject).
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object1) =>
    ///     {
    ///         match TransientObject::allocate(TransientObjectType::Aes, 256) {
    ///             Ok(object2) => {
    ///                 object1.copy_attribute_from(object2);
    ///                 Ok(())
    ///             }
    ///             Err(e) => Err(e),
    ///         }
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the persistentd` object is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If src_object is not initialized.
    /// 2) If self is initialized.
    /// 3) If the type and size of src_object and self are not compatible.
    /// 4) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn copy_attribute_from<T: ObjHandle>(&mut self, src_object: &T) -> Result<()> {
        match unsafe { raw::TEE_CopyObjectAttributes1(self.handle(), src_object.handle()) } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Generates a random key or a key-pair and populates a transient key object with the generated key material.
    ///
    /// # Parameters
    ///
    /// 1) `key_size`: the size of the desired key. It SHALL be less than or equal to
    /// the maximum key size specified when the [TransientObject](TransientObject) was created.
    ///
    /// # Example
    ///
    /// ```no_run
    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
    ///     Ok(object) =>
    ///     {
    ///         object.generate_key(128, &[])?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `BadParameters`: If an incorrect or inconsistent attribute value is detected. In this
    ///    case, the content of the object SHALL remain uninitialized.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If some mandatory attribute is missing.
    /// 3) If an attribute which is not defined for the object’s type is present in attrs.
    /// 4) If an attribute value is too big to fit within the maximum object size specified when
    /// the object was created.
    /// 5) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn generate_key(&self, key_size: usize, params: &[Attribute]) -> Result<()> {
        let p: Vec<raw::TEE_Attribute> = params.iter().map(|p| p.raw()).collect();
        unsafe {
            match raw::TEE_GenerateKey(
                self.handle(),
                key_size as u32,
                p.as_slice().as_ptr() as _,
                p.len() as u32,
            ) {
                raw::TEE_SUCCESS => Ok(()),
                code => Err(Error::from_raw_error(code)),
            }
        }
    }
}

impl ObjHandle for TransientObject {
    fn handle(&self) -> raw::TEE_ObjectHandle {
        self.0.handle()
    }
}

impl Drop for TransientObject {
    /// Deallocates a [TransientObject](TransientObject) previously allocated.
    /// After this function has been called, the object handle is no longer valid and all resources
    /// associated with the [TransientObject](TransientObject) SHALL have been reclaimed.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    fn drop(&mut self) {
        unsafe {
            if self.0.raw != ptr::null_mut() {
                raw::TEE_FreeTransientObject(self.0.handle());
            }
            Box::from_raw(self.0.raw);
        }
    }
}

/// An object identified by an Object Identifier and including a Data Stream.
///
/// Contrast [TransientObject](TransientObject).
pub struct PersistentObject(ObjectHandle);

impl PersistentObject {
    /// Open an existing [PersistentObject](PersistentObject).
    ///
    /// # Parameters
    ///
    /// 1) `storage_id`: The storaget to use which is defined in
    ///    [ObjectStorageConstants](ObjectStorageConstants).
    /// 2) `object_id`: The object identifier. Note that this buffer cannot reside in shared memory.
    /// 3) `flags`: The [DataFlag](DataFlag) which determine the settings under which the object is opened.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_READ) {
    ///     Ok(object) =>
    ///     {
    ///         // ...
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `ItemNotFound`: If the storage denoted by storage_id does not exist or if the object
    ///    identifier cannot be found in the storage.
    /// 2) `Access_Conflict`: If an access right conflict was detected while opening the object.
    /// 3) `OutOfMemory`: If there is not enough memory to complete the operation.
    /// 4) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 5) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object_id.len() >
    ///    [MiscellaneousConstants::TeeObjectIdMaxLen](MiscellaneousConstants::TeeObjectIdMaxLen)
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn open(
        storage_id: ObjectStorageConstants,
        object_id: &[u8],
        flags: DataFlag,
    ) -> Result<Self> {
        let raw_handle: *mut raw::TEE_ObjectHandle = Box::into_raw(Box::new(ptr::null_mut()));
        match unsafe {
            raw::TEE_OpenPersistentObject(
                storage_id as u32,
                object_id.as_ptr() as _,
                object_id.len() as u32,
                flags.bits(),
                raw_handle as *mut _,
            )
        } {
            raw::TEE_SUCCESS => {
                let handle = ObjectHandle::from_raw(raw_handle);
                Ok(Self(handle))
            }
            code => {
                unsafe {
                    Box::from_raw(raw_handle);
                }
                Err(Error::from_raw_error(code))
            }
        }
    }

    /// Create a [PersistentObject](PersistentObject) with initial attributes and an initial data stream content.
    ///
    /// # Parameters
    ///
    /// 1) `storage_id`: The storaget to use which is defined in
    ///    [ObjectStorageConstants](ObjectStorageConstants).
    /// 2) `object_id`: The object identifier. Note that this buffer cannot reside in shared memory.
    /// 3) `flags`: The [DataFlag](DataFlag) which determine the settings under which the object is opened.
    /// 4) `attributes`: A handle on a [PersistentObject](PersistentObject) or an initialized [TransientObject](TransientObject)
    /// from which to take the [PersistentObject](PersistentObject) attributes.
    /// Can be NONE if the [PersistentObject](PersistentObject) contains no attribute.
    /// For example,if  it is a pure data object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// let mut init_data: [u8; 0] = [0; 0];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_READ | DataFlag::ACCESS_WRITE
    ///         None,
    ///         &mut init_data) {
    ///     Ok(object) =>
    ///     {
    ///         // ...
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `ItemNotFound`: If the storage denoted by storage_id does not exist or if the object
    ///    identifier cannot be found in the storage.
    /// 2) `Access_Conflict`: If an access right conflict was detected while opening the object.
    /// 3) `OutOfMemory`: If there is not enough memory to complete the operation.
    /// 4) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 5) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object_id.len() >
    ///    [MiscellaneousConstants::TeeObjectIdMaxLen](MiscellaneousConstants::TeeObjectIdMaxLen).
    /// 2) If attributes is not NONE and is not a valid handle on an initialized object containing
    ///    the type and attributes of the [PersistentObject](PersistentObject) to create.
    /// 3) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn create(
        storage_id: ObjectStorageConstants,
        object_id: &[u8],
        flags: DataFlag,
        attributes: Option<ObjectHandle>,
        initial_data: &[u8],
    ) -> Result<Self> {
        let raw_handle: *mut raw::TEE_ObjectHandle = Box::into_raw(Box::new(ptr::null_mut()));
        let attributes = match attributes {
            Some(a) => a.handle(),
            None => ptr::null_mut(),
        };
        match unsafe {
            raw::TEE_CreatePersistentObject(
                storage_id as u32,
                object_id.as_ptr() as _,
                object_id.len() as u32,
                flags.bits(),
                attributes,
                initial_data.as_ptr() as _,
                initial_data.len() as u32,
                raw_handle as *mut _,
            )
        } {
            raw::TEE_SUCCESS => {
                let handle = ObjectHandle::from_raw(raw_handle);
                Ok(Self(handle))
            }
            code => {
                unsafe {
                    Box::from_raw(raw_handle);
                }
                Err(Error::from_raw_error(code))
            }
        }
    }

    /// Marks an object for deletion and closes the object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_READ) {
    ///     Ok(object) =>
    ///     {
    ///         object.close_and_delete()?;
    ///         std::mem::forget(object);
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    // this function is conflicted with Drop implementation, when use this one to avoid panic:
    // Call `mem::forget` for this structure to avoid double drop the object
    pub fn close_and_delete(&mut self) -> Result<()> {
        match unsafe { raw::TEE_CloseAndDeletePersistentObject1(self.0.handle()) } {
            raw::TEE_SUCCESS => {
                unsafe {
                    Box::from_raw(self.0.raw);
                }
                return Ok(());
            }
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Changes the identifier of an object.
    /// The object SHALL have been opened with the [DataFlag::ACCESS_WRITE_META](DataFlag::ACCESS_WRITE_META) right, which means access to the object is exclusive.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// let new_obj_id = [2u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_WRITE_META) {
    ///     Ok(object) =>
    ///     {
    ///         object.rename(&new_obj_id)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `Access_Conflict`: If an access right conflict was detected while opening the object.
    /// 2) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 3) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If new_object_id resides in shared memory.
    /// 3) If new_object_id.len() >
    ///    [MiscellaneousConstants::TeeObjectIdMaxLen](MiscellaneousConstants::TeeObjectIdMaxLen).
    /// 4) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn rename(&mut self, new_object_id: &[u8]) -> Result<()> {
        match unsafe {
            raw::TEE_RenamePersistentObject(
                self.0.handle(),
                new_object_id.as_ptr() as _,
                new_object_id.len() as u32,
            )
        } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }
    /// Return the characteristics of an object.
    /// Function is similar to [TransientObject::info](TransientObject::info) besides extra errors.
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    pub fn info(&self) -> Result<ObjectInfo> {
        self.0.info()
    }

    /// Restrict the object usage flags of an object handle to contain at most the flags passed in the obj_usage parameter.
    /// Function is similar to [TransientObject::restrict_usage](TransientObject::restrict_usage) besides extra errors.
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    pub fn restrict_usage(&mut self, obj_usage: UsageFlag) -> Result<()> {
        self.0.restrict_usage(obj_usage)
    }

    /// Extract one buffer attribute from an object. The attribute is identified by the argument id.
    /// Function is similar to [TransientObject::ref_attribute](TransientObject::ref_attribute) besides extra errors.
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    pub fn ref_attribute(&self, id: AttributeId, buffer: &mut [u8]) -> Result<usize> {
        self.0.ref_attribute(id, buffer)
    }

    /// Extract one value attribute from an object. The attribute is identified by the argument id.
    /// Function is similar to [TransientObject::value_attribute](TransientObject::value_attribute) besides extra errors.
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    pub fn value_attribute(&self, id: u32) -> Result<(u32, u32)> {
        self.0.value_attribute(id)
    }

    /// Read requested size from the data stream assoicate with the object into the buffer.
    ///
    /// # Parameters
    ///
    /// 1) `buffer`: A pre-allocated buffer for saving the object's data stream.
    /// 2) `count`: The returned value contains the number of bytes read.
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_READ) {
    ///     Ok(object) =>
    ///     {
    ///         let read_buf = [0u8;16];
    ///         object.read(&mut read_buf)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 2) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn read(&self, buf: &mut [u8]) -> Result<u32> {
        let mut count: u32 = 0;
        match unsafe {
            raw::TEE_ReadObjectData(
                self.handle(),
                buf.as_mut_ptr() as _,
                buf.len() as u32,
                &mut count,
            )
        } {
            raw::TEE_SUCCESS => Ok(count),
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Write the passed in buffer data into from the data stream assoicate with the object.
    ///
    /// # Parameters
    ///
    /// 1) `buffer`: A pre-allocated buffer for saving the object's data stream.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_WRITE) {
    ///     Ok(object) =>
    ///     {
    ///         let write_buf = [1u8;16];
    ///         object.write(& write_buf)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `StorageNoSpace`: If insufficient storage space is available.
    /// 2) `Overflow`: If the value of the data position indicator resulting from this operation
    ///    would be greater than
    ///    [MiscellaneousConstants::TeeDataMaxPosition](MiscellaneousConstants::TeeDataMaxPosition).
    /// 3) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 4) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn write(&mut self, buf: &[u8]) -> Result<()> {
        match unsafe {
            raw::TEE_WriteObjectData(self.handle(), buf.as_ptr() as _, buf.len() as u32)
        } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Change the size of a data stream associate with the object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open (
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_WRITE) {
    ///     Ok(object) =>
    ///     {
    ///         object.truncate(1u32)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `StorageNoSpace`: If insufficient storage space is available.
    ///    would be greater than
    ///    [MiscellaneousConstants::TeeDataMaxPosition](MiscellaneousConstants::TeeDataMaxPosition).
    /// 2) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 3) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn truncate(&self, size: u32) -> Result<()> {
        match unsafe { raw::TEE_TruncateObjectData(self.handle(), size) } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Set the data position indicator associate with the object.
    ///
    /// # Parameters
    /// 1) `whence`: Defined in [Whence](Whence).
    /// 2) `offset`: The bytes shifted based on `whence`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// let obj_id = [1u8;1];
    /// match PersistentObject::open(
    ///         ObjectStorageConstants::Private,
    ///         &obj_id,
    ///         DataFlag::ACCESS_WRITE) {
    ///     Ok(object) =>
    ///     {
    ///         object.seek(0i32, Whence::DataSeekSet)?;
    ///         Ok(())
    ///     }
    ///     Err(e) => Err(e),
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// 1) `Overflow`: If data position indicator is greater than
    ///    [MiscellaneousConstants::TeeDataMaxPosition](MiscellaneousConstants::TeeDataMaxPosition).
    /// 2) `CorruptObject`: If the [PersistentObject](PersistentObject) is corrupt. The object handle is closed.
    /// 3) `StorageNotAvailable`: If the [PersistentObject](PersistentObject) is stored in a storage area which is
    ///    currently inaccessible.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    pub fn seek(&self, offset: i32, whence: Whence) -> Result<()> {
        match unsafe { raw::TEE_SeekObjectData(self.handle(), offset, whence.into()) } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }
}

impl ObjHandle for PersistentObject {
    fn handle(&self) -> raw::TEE_ObjectHandle {
        self.0.handle()
    }
}

impl Drop for PersistentObject {
    /// Close an opened [PersistentObject](PersistentObject).
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error associated with this function which is not
    ///    explicitly associated with a defined return code for this function.
    fn drop(&mut self) {
        unsafe {
            if self.0.raw != Box::into_raw(Box::new(ptr::null_mut())) {
                raw::TEE_CloseObject(self.0.handle());
            }
            Box::from_raw(self.0.raw);
        }
    }
}

// The examples and detailed function explanation will be added after we test this struct and its
// functions.
/// An enumerator for [PersistentObject](PersistentObject)s.
pub struct ObjectEnumHandle {
    raw: *mut raw::TEE_ObjectEnumHandle,
}

impl ObjectEnumHandle {
    /// Allocate an object enumerator.
    /// Once an object enumerator has been allocated, it can be reused for multiple enumerations.
    pub fn allocate() -> Result<Self> {
        let raw_handle: *mut raw::TEE_ObjectEnumHandle = Box::into_raw(Box::new(ptr::null_mut()));
        match unsafe { raw::TEE_AllocatePersistentObjectEnumerator(raw_handle) } {
            raw::TEE_SUCCESS => Ok(Self { raw: raw_handle }),
            code => {
                unsafe {
                    Box::from_raw(raw_handle);
                }
                Err(Error::from_raw_error(code))
            }
        }
    }

    /// Reset an object enumerator handle to its initial state after allocation.
    /// If an enumeration has been started, it is stopped.
    pub fn reset(&mut self) {
        unsafe {
            raw::TEE_ResetPersistentObjectEnumerator(*self.raw);
        }
    }

    /// Start the enumeration of all the [PersistentObject](PersistentObject)s in a given Trusted Storage.
    /// The object information can be retrieved by calling the function
    /// [ObjectEnumHandle::get_next](ObjectEnumHandle::get_next) repeatedly.
    pub fn start(&mut self, storage_id: u32) -> Result<()> {
        match unsafe { raw::TEE_StartPersistentObjectEnumerator(*self.raw, storage_id) } {
            raw::TEE_SUCCESS => Ok(()),
            code => Err(Error::from_raw_error(code)),
        }
    }

    /// Get the next object in an enumeration and returns information about the object: type, size, identifier, etc.
    pub fn get_next<T>(
        &mut self,
        object_info: &mut ObjectInfo,
        object_id: &mut [u8],
    ) -> Result<u32> {
        let mut object_id_len: u32 = 0;
        match unsafe {
            raw::TEE_GetNextPersistentObject(
                *self.raw,
                &mut object_info.raw,
                object_id.as_mut_ptr() as _,
                &mut object_id_len,
            )
        } {
            raw::TEE_SUCCESS => Ok(object_id_len),
            code => Err(Error::from_raw_error(code)),
        }
    }
}

impl Drop for ObjectEnumHandle {
    /// Deallocates all resources associated with an object enumerator handle. After this function is called, the handle is no longer valid.
    ///
    /// # Panics
    ///
    /// 1) If object is not a valid opened object.
    /// 2) If the Implementation detects any other error.
    fn drop(&mut self) {
        unsafe {
            raw::TEE_FreePersistentObjectEnumerator(*self.raw);
            Box::from_raw(self.raw);
        }
    }
}
