use crate::error::{Error, Result};
use crate::{Encoding, Length, Tag};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
struct LengthFixup {
length_position: usize,
reserved_bytes: usize,
content_start: usize,
}
pub struct Encoder {
buffer: Vec<u8>,
encoding: Encoding,
length_stack: Vec<LengthFixup>,
}
impl Encoder {
pub fn new(encoding: Encoding) -> Self {
Self {
buffer: Vec::new(),
encoding,
length_stack: Vec::new(),
}
}
pub fn with_capacity(encoding: Encoding, capacity: usize) -> Self {
Self {
buffer: Vec::with_capacity(capacity),
encoding,
length_stack: Vec::new(),
}
}
pub fn encoding(&self) -> Encoding {
self.encoding
}
pub fn write_tag(&mut self, tag: Tag) -> Result<()> {
tag.encode(&mut self.buffer)
}
pub fn write_length(&mut self, length: usize) -> Result<()> {
Length::Definite(length).encode(&mut self.buffer)
}
pub fn write_bytes(&mut self, bytes: &[u8]) {
self.buffer.extend_from_slice(bytes);
}
pub fn encode<T: crate::traits::Encode>(&mut self, value: &T) -> Result<()> {
value.encode(self)
}
pub fn encode_with_tag<T: crate::traits::Encode>(&mut self, tag: Tag, value: &T) -> Result<()> {
self.write_tag(tag)?;
let len = value.encoded_len()?;
self.write_length(len)?;
value.encode(self)
}
pub fn start_constructed(&mut self, tag: Tag) -> Result<ConstructedGuard<'_>> {
self.write_tag(tag)?;
let length_position = self.buffer.len();
self.buffer.extend_from_slice(&[0; 5]);
let content_start = self.buffer.len();
self.length_stack.push(LengthFixup {
length_position,
reserved_bytes: 5,
content_start,
});
Ok(ConstructedGuard { encoder: self })
}
pub fn finish(mut self) -> Result<Vec<u8>> {
if !self.length_stack.is_empty() {
return Err(Error::UnfinishedConstructed);
}
self.buffer.shrink_to_fit();
Ok(self.buffer)
}
pub fn start_constructed_no_guard(&mut self, tag: Tag) -> Result<()> {
self.write_tag(tag)?;
let length_position = self.buffer.len();
self.buffer.extend_from_slice(&[0; 5]);
let content_start = self.buffer.len();
self.length_stack.push(LengthFixup {
length_position,
reserved_bytes: 5,
content_start,
});
Ok(())
}
pub fn end_constructed(&mut self) -> Result<()> {
self.backpatch_length()
}
fn backpatch_length(&mut self) -> Result<()> {
let fixup = self
.length_stack
.pop()
.ok_or(Error::NoConstructedToFinish)?;
let content_len = self.buffer.len() - fixup.content_start;
let mut length_bytes = Vec::with_capacity(5);
Length::Definite(content_len).encode(&mut length_bytes)?;
let actual_length_bytes = length_bytes.len();
if actual_length_bytes > fixup.reserved_bytes {
return Err(Error::LengthTooLarge);
}
let excess = fixup.reserved_bytes - actual_length_bytes;
if excess > 0 {
let content_start = fixup.content_start;
let new_content_start = fixup.length_position + actual_length_bytes;
self.buffer.copy_within(content_start.., new_content_start);
self.buffer.truncate(self.buffer.len() - excess);
}
self.buffer[fixup.length_position..fixup.length_position + actual_length_bytes]
.copy_from_slice(&length_bytes);
Ok(())
}
}
pub struct ConstructedGuard<'a> {
encoder: &'a mut Encoder,
}
impl<'a> ConstructedGuard<'a> {
pub fn encode<T: crate::traits::Encode>(&mut self, value: &T) -> Result<()> {
self.encoder.encode(value)
}
pub fn write_tag(&mut self, tag: Tag) -> Result<()> {
self.encoder.write_tag(tag)
}
pub fn write_length(&mut self, length: usize) -> Result<()> {
self.encoder.write_length(length)
}
pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.encoder.buffer.extend_from_slice(bytes);
Ok(())
}
pub fn finish(self) -> Result<()> {
Ok(())
}
}
impl Drop for ConstructedGuard<'_> {
fn drop(&mut self) {
let _ = self.encoder.backpatch_length();
}
}