use crate::canonical::{CanonicalCbor, CanonicalCborRef};
use crate::profile::{
is_strictly_increasing_encoded, validate_bignum_bytes, validate_int_safe_i64,
};
use crate::query::CborValueRef;
use crate::value::{BigInt, CborInteger, CborValue, F64Bits, ValueRepr};
use crate::{CborError, ErrorCode};
use alloc::vec::Vec;
#[derive(Clone, Copy)]
enum Frame<'a> {
Value(&'a CborValue),
TextKey(&'a str),
}
struct SmallStack<'a, const N: usize> {
inline: [Option<Frame<'a>>; N],
len: usize,
overflow: Vec<Frame<'a>>,
}
impl<'a, const N: usize> SmallStack<'a, N> {
const fn new() -> Self {
Self {
inline: [None; N],
len: 0,
overflow: Vec::new(),
}
}
fn push(&mut self, frame: Frame<'a>) {
if !self.overflow.is_empty() {
self.overflow.push(frame);
return;
}
if self.len < N {
self.inline[self.len] = Some(frame);
self.len += 1;
} else {
self.overflow.push(frame);
}
}
fn pop(&mut self) -> Option<Frame<'a>> {
if let Some(frame) = self.overflow.pop() {
return Some(frame);
}
if self.len == 0 {
return None;
}
self.len -= 1;
self.inline[self.len].take()
}
}
pub fn encode_to_vec(value: &CborValue) -> Result<Vec<u8>, CborError> {
let mut sink = VecSink::new();
encode_value(&mut sink, value)?;
Ok(sink.into_vec())
}
#[cfg(feature = "sha2")]
pub fn encode_sha256(value: &CborValue) -> Result<[u8; 32], CborError> {
use sha2::{Digest, Sha256};
let mut sink = HashSink::new(Sha256::new());
encode_value(&mut sink, value)?;
let out = sink.hasher.finalize();
let mut digest = [0u8; 32];
digest.copy_from_slice(out.as_slice());
Ok(digest)
}
trait Sink {
fn write(&mut self, bytes: &[u8]) -> Result<(), CborError>;
fn write_u8(&mut self, byte: u8) -> Result<(), CborError> {
self.write(&[byte])
}
fn position(&self) -> usize;
}
struct VecSink {
buf: Vec<u8>,
}
impl VecSink {
const fn new() -> Self {
Self { buf: Vec::new() }
}
fn into_vec(self) -> Vec<u8> {
self.buf
}
fn reserve(&mut self, additional: usize) -> Result<(), CborError> {
self.buf
.try_reserve(additional)
.map_err(|_| CborError::new(ErrorCode::AllocationFailed, self.buf.len()))?;
Ok(())
}
}
impl Sink for VecSink {
fn write(&mut self, bytes: &[u8]) -> Result<(), CborError> {
self.reserve(bytes.len())?;
self.buf.extend_from_slice(bytes);
Ok(())
}
fn write_u8(&mut self, byte: u8) -> Result<(), CborError> {
self.reserve(1)?;
self.buf.push(byte);
Ok(())
}
fn position(&self) -> usize {
self.buf.len()
}
}
#[cfg(feature = "sha2")]
struct HashSink<D> {
hasher: D,
len: usize,
}
#[cfg(feature = "sha2")]
impl<D> HashSink<D> {
const fn new(hasher: D) -> Self {
Self { hasher, len: 0 }
}
}
#[cfg(feature = "sha2")]
impl<D: sha2::Digest> Sink for HashSink<D> {
fn write(&mut self, bytes: &[u8]) -> Result<(), CborError> {
self.hasher.update(bytes);
self.len = self.len.saturating_add(bytes.len());
Ok(())
}
fn position(&self) -> usize {
self.len
}
}
fn encode_value<S: Sink>(sink: &mut S, value: &CborValue) -> Result<(), CborError> {
let mut stack = SmallStack::<64>::new();
stack.push(Frame::Value(value));
while let Some(frame) = stack.pop() {
match frame {
Frame::TextKey(key) => {
encode_text(sink, key)?;
}
Frame::Value(v) => match v.repr() {
ValueRepr::Integer(i) => encode_integer(sink, i)?,
ValueRepr::Bytes(b) => encode_bytes(sink, b)?,
ValueRepr::Text(s) => encode_text(sink, s)?,
ValueRepr::Array(items) => {
encode_major_len(sink, 4, items.len())?;
for item in items.iter().rev() {
stack.push(Frame::Value(item));
}
}
ValueRepr::Map(map) => {
encode_major_len(sink, 5, map.len())?;
for (k, v) in map.entries().iter().rev() {
stack.push(Frame::Value(v));
stack.push(Frame::TextKey(k));
}
}
ValueRepr::Bool(false) => sink.write_u8(0xf4)?,
ValueRepr::Bool(true) => sink.write_u8(0xf5)?,
ValueRepr::Null => sink.write_u8(0xf6)?,
ValueRepr::Float(bits) => encode_float64(sink, *bits)?,
},
}
}
Ok(())
}
fn err_at<S: Sink>(sink: &S, code: ErrorCode) -> CborError {
CborError::new(code, sink.position())
}
fn encode_integer<S: Sink>(sink: &mut S, value: &CborInteger) -> Result<(), CborError> {
if let Some(v) = value.as_i64() {
return encode_int(sink, v);
}
let b = value
.as_bigint()
.ok_or_else(|| err_at(sink, ErrorCode::LengthOverflow))?;
encode_bignum(sink, b)
}
fn encode_int<S: Sink>(sink: &mut S, v: i64) -> Result<(), CborError> {
if v >= 0 {
let u = u64::try_from(v).map_err(|_| err_at(sink, ErrorCode::LengthOverflow))?;
encode_major_uint(sink, 0, u)
} else {
let n_i128 = -1_i128 - i128::from(v);
let n_u64 = u64::try_from(n_i128).map_err(|_| err_at(sink, ErrorCode::LengthOverflow))?;
encode_major_uint(sink, 1, n_u64)
}
}
fn encode_bignum<S: Sink>(sink: &mut S, b: &BigInt) -> Result<(), CborError> {
let tag = if b.is_negative() { 3u64 } else { 2u64 };
encode_major_uint(sink, 6, tag)?;
encode_bytes(sink, b.magnitude())
}
fn encode_bytes<S: Sink>(sink: &mut S, bytes: &[u8]) -> Result<(), CborError> {
encode_major_len(sink, 2, bytes.len())?;
sink.write(bytes)
}
fn encode_text<S: Sink>(sink: &mut S, s: &str) -> Result<(), CborError> {
let b = s.as_bytes();
encode_major_len(sink, 3, b.len())?;
sink.write(b)
}
fn encode_float64<S: Sink>(sink: &mut S, bits: F64Bits) -> Result<(), CborError> {
let raw = bits.bits();
let mut buf = [0u8; 9];
buf[0] = 0xfb;
buf[1..9].copy_from_slice(&raw.to_be_bytes());
sink.write(&buf)
}
fn encode_major_len<S: Sink>(sink: &mut S, major: u8, len: usize) -> Result<(), CborError> {
let len_u64 = u64::try_from(len).map_err(|_| err_at(sink, ErrorCode::LengthOverflow))?;
encode_major_uint(sink, major, len_u64)
}
fn encode_major_uint<S: Sink>(sink: &mut S, major: u8, value: u64) -> Result<(), CborError> {
debug_assert!(major <= 7);
if let Ok(v8) = u8::try_from(value) {
if v8 < 24 {
return sink.write_u8((major << 5) | v8);
}
sink.write_u8((major << 5) | 24)?;
return sink.write_u8(v8);
}
if let Ok(v16) = u16::try_from(value) {
sink.write_u8((major << 5) | 25)?;
return sink.write(&v16.to_be_bytes());
}
if let Ok(v32) = u32::try_from(value) {
sink.write_u8((major << 5) | 26)?;
return sink.write(&v32.to_be_bytes());
}
sink.write_u8((major << 5) | 27)?;
sink.write(&value.to_be_bytes())
}
pub struct CanonicalEncoder {
sink: VecSink,
}
impl CanonicalEncoder {
#[must_use]
pub const fn new() -> Self {
Self {
sink: VecSink::new(),
}
}
#[must_use]
pub fn into_vec(self) -> Vec<u8> {
self.sink.into_vec()
}
#[must_use]
pub fn into_canonical(self) -> CanonicalCbor {
CanonicalCbor::new_unchecked(self.into_vec())
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.sink.buf
}
pub fn null(&mut self) -> Result<(), CborError> {
self.sink.write_u8(0xf6)
}
pub fn bool(&mut self, v: bool) -> Result<(), CborError> {
self.sink.write_u8(if v { 0xf5 } else { 0xf4 })
}
pub fn int(&mut self, v: i64) -> Result<(), CborError> {
validate_int_safe_i64(v).map_err(|code| CborError::new(code, 0))?;
encode_int(&mut self.sink, v)
}
pub fn bignum(&mut self, negative: bool, magnitude: &[u8]) -> Result<(), CborError> {
validate_bignum_bytes(negative, magnitude).map_err(|code| CborError::new(code, 0))?;
let tag = if negative { 3u64 } else { 2u64 };
encode_major_uint(&mut self.sink, 6, tag)?;
encode_bytes(&mut self.sink, magnitude)
}
pub fn bytes(&mut self, b: &[u8]) -> Result<(), CborError> {
encode_bytes(&mut self.sink, b)
}
pub fn text(&mut self, s: &str) -> Result<(), CborError> {
encode_text(&mut self.sink, s)
}
pub fn float(&mut self, bits: F64Bits) -> Result<(), CborError> {
encode_float64(&mut self.sink, bits)
}
pub fn value(&mut self, v: &CborValue) -> Result<(), CborError> {
encode_value(&mut self.sink, v)
}
pub fn raw_cbor(&mut self, v: CanonicalCborRef<'_>) -> Result<(), CborError> {
self.sink.write(v.as_bytes())
}
pub fn raw_value_ref(&mut self, v: CborValueRef<'_>) -> Result<(), CborError> {
self.sink.write(v.as_bytes())
}
pub fn array<F>(&mut self, len: usize, f: F) -> Result<(), CborError>
where
F: FnOnce(&mut ArrayEncoder<'_>) -> Result<(), CborError>,
{
encode_major_len(&mut self.sink, 4, len)?;
let mut a = ArrayEncoder {
enc: self,
remaining: len,
};
f(&mut a)?;
if a.remaining != 0 {
return Err(CborError::new(
ErrorCode::ArrayLenMismatch,
self.sink.position(),
));
}
Ok(())
}
pub fn map<F>(&mut self, len: usize, f: F) -> Result<(), CborError>
where
F: FnOnce(&mut MapEncoder<'_>) -> Result<(), CborError>,
{
encode_major_len(&mut self.sink, 5, len)?;
let mut m = MapEncoder {
enc: self,
remaining: len,
prev_key_range: None,
};
f(&mut m)?;
if m.remaining != 0 {
return Err(CborError::new(
ErrorCode::MapLenMismatch,
self.sink.position(),
));
}
Ok(())
}
#[doc(hidden)]
#[allow(missing_docs)]
pub fn __encode_any<T>(&mut self, v: T) -> Result<(), CborError>
where
T: crate::__cbor_macro::IntoCborBytes,
{
crate::__cbor_macro::IntoCborBytes::into_cbor_bytes(v, self)
}
}
impl Default for CanonicalEncoder {
fn default() -> Self {
Self::new()
}
}
pub struct ArrayEncoder<'a> {
enc: &'a mut CanonicalEncoder,
remaining: usize,
}
#[allow(missing_docs)]
impl ArrayEncoder<'_> {
fn consume_one(&mut self) -> Result<(), CborError> {
if self.remaining == 0 {
return Err(CborError::new(
ErrorCode::ArrayLenMismatch,
self.enc.sink.position(),
));
}
self.remaining -= 1;
Ok(())
}
pub fn null(&mut self) -> Result<(), CborError> {
self.consume_one()?;
self.enc.null()
}
pub fn bool(&mut self, v: bool) -> Result<(), CborError> {
self.consume_one()?;
self.enc.bool(v)
}
pub fn int(&mut self, v: i64) -> Result<(), CborError> {
self.consume_one()?;
self.enc.int(v)
}
pub fn bignum(&mut self, negative: bool, magnitude: &[u8]) -> Result<(), CborError> {
self.consume_one()?;
self.enc.bignum(negative, magnitude)
}
pub fn bytes(&mut self, b: &[u8]) -> Result<(), CborError> {
self.consume_one()?;
self.enc.bytes(b)
}
pub fn text(&mut self, s: &str) -> Result<(), CborError> {
self.consume_one()?;
self.enc.text(s)
}
pub fn float(&mut self, bits: F64Bits) -> Result<(), CborError> {
self.consume_one()?;
self.enc.float(bits)
}
pub fn value(&mut self, v: &CborValue) -> Result<(), CborError> {
self.consume_one()?;
self.enc.value(v)
}
pub fn raw_cbor(&mut self, v: CanonicalCborRef<'_>) -> Result<(), CborError> {
self.consume_one()?;
self.enc.raw_cbor(v)
}
pub fn raw_value_ref(&mut self, v: CborValueRef<'_>) -> Result<(), CborError> {
self.consume_one()?;
self.enc.raw_value_ref(v)
}
pub fn array<F>(&mut self, len: usize, f: F) -> Result<(), CborError>
where
F: FnOnce(&mut ArrayEncoder<'_>) -> Result<(), CborError>,
{
self.consume_one()?;
self.enc.array(len, f)
}
pub fn map<F>(&mut self, len: usize, f: F) -> Result<(), CborError>
where
F: FnOnce(&mut MapEncoder<'_>) -> Result<(), CborError>,
{
self.consume_one()?;
self.enc.map(len, f)
}
#[doc(hidden)]
#[allow(missing_docs)]
pub fn __encode_any<T>(&mut self, v: T) -> Result<(), CborError>
where
T: crate::__cbor_macro::IntoCborBytes,
{
self.consume_one()?;
crate::__cbor_macro::IntoCborBytes::into_cbor_bytes(v, self.enc)
}
}
pub struct MapEncoder<'a> {
enc: &'a mut CanonicalEncoder,
remaining: usize,
prev_key_range: Option<(usize, usize)>,
}
#[allow(missing_docs)]
impl MapEncoder<'_> {
pub fn entry<F>(&mut self, key: &str, f: F) -> Result<(), CborError>
where
F: FnOnce(&mut CanonicalEncoder) -> Result<(), CborError>,
{
if self.remaining == 0 {
return Err(CborError::new(
ErrorCode::MapLenMismatch,
self.enc.sink.position(),
));
}
let key_start = self.enc.sink.buf.len();
encode_text(&mut self.enc.sink, key)?;
let key_end = self.enc.sink.buf.len();
if let Some((ps, pe)) = self.prev_key_range {
let prev = &self.enc.sink.buf[ps..pe];
let curr = &self.enc.sink.buf[key_start..key_end];
if prev == curr {
return Err(CborError::new(
ErrorCode::DuplicateMapKey,
self.enc.sink.position(),
));
}
if !is_strictly_increasing_encoded(prev, curr) {
return Err(CborError::new(
ErrorCode::NonCanonicalMapOrder,
self.enc.sink.position(),
));
}
}
self.prev_key_range = Some((key_start, key_end));
f(self.enc)?;
self.remaining -= 1;
Ok(())
}
}