use core::mem::MaybeUninit;
use core::ops::Deref;
use core::slice::from_raw_parts;
use super::{
MAX_CONTAINER_DEPTH, MAX_DEPTH, MAX_SIGNATURE, Signature, SignatureBuf, SignatureError,
SignatureErrorKind,
};
#[derive(Clone)]
pub struct SignatureBuilder {
data: [MaybeUninit<u8>; MAX_SIGNATURE],
init: usize,
structs: usize,
arrays: usize,
}
impl SignatureBuilder {
#[doc(hidden)]
pub const fn new() -> Self {
Self {
data: unsafe { MaybeUninit::uninit().assume_init() },
init: 0,
structs: 0,
arrays: 0,
}
}
#[doc(hidden)]
pub fn from_owned_signature(signature: SignatureBuf) -> Self {
let (data, init) = signature.into_raw_parts();
Self {
data,
init,
structs: 0,
arrays: 0,
}
}
pub fn to_signature(&self) -> &Signature {
unsafe { Signature::new_unchecked(self.as_slice()) }
}
pub fn open_array(&mut self) -> Result<(), SignatureError> {
if self.arrays == MAX_CONTAINER_DEPTH || self.structs + self.arrays == MAX_DEPTH {
return Err(SignatureError::new(
SignatureErrorKind::ExceededMaximumArrayRecursion,
));
}
if !self.push(b'a') {
return Err(SignatureError::new(SignatureErrorKind::SignatureTooLong));
}
self.arrays += 1;
Ok(())
}
pub fn close_array(&mut self) {
self.arrays -= 1;
}
pub fn open_struct(&mut self) -> Result<(), SignatureError> {
if self.structs == MAX_CONTAINER_DEPTH || self.structs + self.arrays == MAX_DEPTH {
return Err(SignatureError::new(
SignatureErrorKind::ExceededMaximumStructRecursion,
));
}
if !self.push(b'(') {
return Err(SignatureError::new(SignatureErrorKind::SignatureTooLong));
}
self.structs += 1;
Ok(())
}
pub fn close_struct(&mut self) -> Result<(), SignatureError> {
if !self.push(b')') {
return Err(SignatureError::new(SignatureErrorKind::SignatureTooLong));
}
self.structs -= 1;
Ok(())
}
pub fn open_dict(&mut self) -> Result<(), SignatureError> {
if self.structs == MAX_CONTAINER_DEPTH || self.structs + self.arrays == MAX_DEPTH {
return Err(SignatureError::new(
SignatureErrorKind::ExceededMaximumDictRecursion,
));
}
if !self.push(b'{') {
return Err(SignatureError::new(SignatureErrorKind::SignatureTooLong));
}
self.structs += 1;
Ok(())
}
pub fn close_dict(&mut self) -> Result<(), SignatureError> {
if !self.push(b'}') {
return Err(SignatureError::new(SignatureErrorKind::SignatureTooLong));
}
self.structs -= 1;
Ok(())
}
fn push(&mut self, byte: u8) -> bool {
if self.init == MAX_SIGNATURE {
return false;
}
unsafe {
self.data
.as_mut_ptr()
.cast::<u8>()
.add(self.init)
.write(byte);
self.init += 1;
}
true
}
pub fn clear(&mut self) {
self.init = 0;
}
#[must_use = "Return value must be observed to indicate an error"]
pub fn extend_from_signature<S>(&mut self, other: S) -> bool
where
S: AsRef<Signature>,
{
let bytes = other.as_ref().as_bytes();
if self.init + bytes.len() > MAX_SIGNATURE {
return false;
}
unsafe {
self.data
.as_mut_ptr()
.cast::<u8>()
.add(self.init)
.copy_from(bytes.as_ptr(), bytes.len());
self.init += bytes.len();
}
true
}
#[inline]
fn as_slice(&self) -> &[u8] {
unsafe { from_raw_parts(self.data.as_ptr().cast(), self.init) }
}
}
impl Deref for SignatureBuilder {
type Target = Signature;
#[inline]
fn deref(&self) -> &Self::Target {
self.to_signature()
}
}
impl PartialEq<SignatureBuilder> for SignatureBuilder {
#[inline]
fn eq(&self, other: &SignatureBuilder) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl Eq for SignatureBuilder {}