use std::ffi::CStr;
use std::ffi::CString;
use libc::EINVAL;
use serde::Deserialize;
use serde::Serialize;
use crate::descriptor::AsRawDescriptor;
use crate::descriptor::SafeDescriptor;
use crate::Error;
use crate::RawDescriptor;
use crate::Result;
#[derive(Debug, Deserialize, Serialize)]
pub struct SharedMemory {
    #[serde(with = "crate::with_as_descriptor")]
    pub descriptor: SafeDescriptor,
    pub size: u64,
}
pub(crate) trait PlatformSharedMemory {
    fn new(debug_name: &CStr, size: u64) -> Result<SharedMemory>;
    fn from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory>;
}
impl SharedMemory {
    pub fn new<T: Into<Vec<u8>>>(debug_name: T, size: u64) -> Result<SharedMemory> {
        let debug_name = CString::new(debug_name).map_err(|_| super::Error::new(EINVAL))?;
        <SharedMemory as PlatformSharedMemory>::new(&debug_name, size)
    }
    pub fn size(&self) -> u64 {
        self.size
    }
    pub fn from_safe_descriptor(descriptor: SafeDescriptor, size: u64) -> Result<SharedMemory> {
        <SharedMemory as PlatformSharedMemory>::from_safe_descriptor(descriptor, size)
    }
    pub fn try_clone(&self) -> Result<SharedMemory> {
        Ok(SharedMemory {
            descriptor: self.descriptor.try_clone()?,
            size: self.size,
        })
    }
}
impl AsRawDescriptor for SharedMemory {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.descriptor.as_raw_descriptor()
    }
}
impl From<SharedMemory> for SafeDescriptor {
    fn from(sm: SharedMemory) -> SafeDescriptor {
        sm.descriptor
    }
}
impl audio_streams::shm_streams::SharedMemory for SharedMemory {
    type Error = Error;
    fn anon(size: u64) -> Result<Self> {
        SharedMemory::new("shm_streams", size)
    }
    fn size(&self) -> u64 {
        self.size()
    }
    #[cfg(any(target_os = "android", target_os = "linux"))]
    fn as_raw_fd(&self) -> RawDescriptor {
        self.as_raw_descriptor()
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn new_1024() {
        let shm = SharedMemory::new("test", 1024).expect("failed to create shared memory");
        assert_eq!(shm.size(), 1024);
    }
    #[test]
    fn new_1028() {
        let shm = SharedMemory::new("name", 1028).expect("failed to create shared memory");
        assert_eq!(shm.size(), 1028);
    }
    #[test]
    fn new_too_huge() {
        SharedMemory::new("test", 0x8000_0000_0000_0000)
            .expect_err("8 exabyte shared memory creation should fail");
    }
}