use crate::{Error, Marker, WriteBuffer};

/// Encode the length of a string and the string itself.
pub fn write_str(buf: &mut WriteBuffer, value: &str) -> Result<Marker, Error> {
    if !value.is_ascii() {
        return Err(Error::BadEncoding);
    }

    let len = value.len();
    let (marker, bytes): (_, &[u8]) = if len <= 0x1f {
        (Marker::ImmStr { len: len as _ }, &[])
    } else if len < u8::MAX as _ {
        (Marker::S8, &u8::to_be_bytes(len as _))
    } else if len < u16::MAX as _ {
        (Marker::S16, &u16::to_be_bytes(len as _))
    } else if len < u32::MAX as _ {
        (Marker::S32, &u32::to_be_bytes(len as _))
    } else {
        return Err(Error::OutOfRange);
    };

    buf.write(len + 1 + bytes.len(), |buf| {
        // Safety: bytes.len() + len + 1 bytes available in buf.
        unsafe {
            let buf = buf.as_mut_ptr();
            *buf = marker.encoding();

            let buf = buf.add(1);
            buf.copy_from_nonoverlapping(bytes.as_ptr(), bytes.len());

            let buf = buf.add(bytes.len());
            buf.copy_from_nonoverlapping(value.as_bytes().as_ptr(), len);
        }
    })?;

    Ok(marker)
}
