use super::Event;
use crate::{
error::{self, Error},
field::WireType,
message::Element,
string,
};
use core::str;
pub(crate) trait Decodable {
fn decode<'a>(&mut self, input: &mut &'a [u8]) -> Result<Option<Event<'a>>, Error>;
fn decode_dynamically_sized_value<'a>(
&mut self,
expected_type: WireType,
input: &mut &'a [u8],
) -> Result<&'a [u8], Error>;
fn decode_uint64(&mut self, input: &mut &[u8]) -> Result<u64, Error> {
match self.decode(input)? {
Some(Event::UInt64(value)) => Ok(value),
_ => Err(error::Kind::Decode {
element: Element::Value,
wire_type: WireType::UInt64,
}
.into()),
}
}
fn decode_sint64(&mut self, input: &mut &[u8]) -> Result<i64, Error> {
match self.decode(input)? {
Some(Event::SInt64(value)) => Ok(value),
_ => Err(error::Kind::Decode {
element: Element::Value,
wire_type: WireType::SInt64,
}
.into()),
}
}
fn decode_bytes<'a>(&mut self, input: &mut &'a [u8]) -> Result<&'a [u8], Error> {
self.decode_dynamically_sized_value(WireType::Bytes, input)
}
fn decode_string<'a>(&mut self, input: &mut &'a [u8]) -> Result<&'a str, Error> {
let bytes = self.decode_dynamically_sized_value(WireType::String, input)?;
let s = str::from_utf8(bytes).map_err(|e| error::Kind::Utf8 {
valid_up_to: e.valid_up_to(),
})?;
string::ensure_canonical(s)
}
fn decode_message<'a>(&mut self, input: &mut &'a [u8]) -> Result<&'a [u8], Error> {
self.decode_dynamically_sized_value(WireType::Message, input)
}
fn decode_sequence<'a>(
&mut self,
expected_type: WireType,
input: &mut &'a [u8],
) -> Result<&'a [u8], Error> {
let length = match self.decode(input)? {
Some(Event::SequenceHeader { wire_type, length }) if wire_type == expected_type => {
length
}
_ => {
return Err(error::Kind::Decode {
element: Element::SequenceHeader,
wire_type: expected_type,
}
.into())
}
};
match self.decode(input)? {
Some(Event::ValueChunk {
bytes, remaining, ..
}) => {
if remaining == 0 {
debug_assert_eq!(length, bytes.len());
Ok(bytes)
} else {
Err(error::Kind::Truncated {
remaining,
wire_type: WireType::Sequence,
}
.into())
}
}
_ => Err(error::Kind::Decode {
element: Element::Value,
wire_type: WireType::Sequence,
}
.into()),
}
}
}