use crate::v4::error::Result;
use serde::{Deserialize, Serialize};
use std::ffi::{CStr, CString};

/// Similar to the SName struct, used for the fixed-length Message sname field,
/// but is a variable-length option used for the Message options field.
///
/// A null-terminated string with min-length 1.
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct SNameOption(CString);

impl SNameOption {
    /// Construct a valid sname field.
    pub fn new(name: &CStr) -> Result<Self> {
        if name.count_bytes() + 1 >= 255 {
            return Err("Larger than 255 octets for a single option");
        }

        Ok(Self(name.to_owned()))
    }

    /// Get the `CString` that this type wraps.
    pub fn to_string(self) -> CString {
        self.0
    }

    /// Get the length of SNameOption (WITH the null byte).
    pub fn len(&self) -> usize {
        self.0.count_bytes() + 1
    }

    #[inline]
    /// Used to encode the variable-length option.
    pub fn extend_into(&self, bytes: &mut Vec<u8>, tag: u8) {
        bytes.push(tag); // tag
        bytes.push(self.len() as u8); // length
        bytes.extend_from_slice(self.0.to_bytes_with_nul()); // value
    }
}

impl From<&[u8]> for SNameOption {
    fn from(value: &[u8]) -> Self {
        Self(CStr::from_bytes_with_nul(value).unwrap().to_owned())
    }
}
