Skip to content

Commit

Permalink
Pushdown automaton Decoder and Decode* traits; log feature
Browse files Browse the repository at this point in the history
Adds a new `veriform::decoder::Decoder` type implemented as a proper
stack-driven pushdown automaton which keeps state across nested
messages.

The primary use case of a stateful decoder automaton is computing
content hashes of messages even in the presence of unknown fields.

Additionally adds a new set of `Decode*` traits which:

- Are generic around their return type and use it to infer the wire type
- Accept a stateful `Decoder` type which exists for the duration of
  processing a message structure, allowing it to compute content hashes
  of messages as they're decoded

Finally, this commit also adds a `log` feature with some basic tracing
of how messages are decoded, which can help assist in debugging the
decoder.

Mea culpa for not splitting these things into separate domain-specific
commits, but this PR in particular has been difficult to wrangle.
  • Loading branch information
tony-iqlusion committed Apr 22, 2020
1 parent c0d7c3a commit f126e46
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 55 deletions.
64 changes: 64 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ keywords = ["hashing", "merkle", "protobufs", "security", "serialization"]

[dependencies]
displaydoc = { version = "0.1", default-features = false }
heapless = "0.5"
log = { version = "0.4", optional = true }
tai64 = { version = "3", optional = true, default-features = false }
uuid = { version = "0.8", optional = true, default-features = false }
vint64 = { version = "1", path = "vint64" }
Expand Down
4 changes: 2 additions & 2 deletions rust/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
//! These are the equivalent of Protobufs' "well-known types"
#[cfg(feature = "tai64")]
mod tai64;
mod timestamp;

#[cfg(feature = "uuid")]
mod uuid;

#[cfg(feature = "tai64")]
pub use self::tai64::TAI64N;
pub use self::timestamp::Timestamp;

#[cfg(feature = "uuid")]
pub use self::uuid::Uuid;
30 changes: 9 additions & 21 deletions rust/src/builtins/tai64.rs → rust/src/builtins/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,21 @@
//! In Veriform these are encoded as:
//!
//! ```text
//! message TAI64N {
//! message Timestamp {
//! secs[0]: !bytes(size = 8),
//! nanos[1]: bytes(size = 4)
//! }
//! ```
pub use tai64::TAI64N;
pub use tai64::TAI64N as Timestamp;

use crate::{
decoder::{Decodable, Decoder},
encoder::Encoder,
error::Error,
field::{self, WireType},
message::Message,
};
use crate::{decoder::Decode, field, Decoder, Encoder, Error, Message};
use core::convert::TryInto;

impl Message for TAI64N {
fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
let mut bytes = bytes.as_ref();
let mut decoder = Decoder::new();

decoder.decode_expected_header(&mut bytes, 0, WireType::UInt64)?;
let secs = decoder.decode_uint64(&mut bytes)?;

decoder.decode_expected_header(&mut bytes, 1, WireType::UInt64)?;
let nanos = decoder.decode_uint64(&mut bytes)?;
impl Message for Timestamp {
fn decode(decoder: &mut Decoder, mut input: &[u8]) -> Result<Self, Error> {
let secs: u64 = decoder.decode(0, &mut input)?;
let nanos: u64 = decoder.decode(1, &mut input)?;

if nanos > core::u32::MAX as u64 {
return Err(Error::Length);
Expand All @@ -55,8 +43,8 @@ impl Message for TAI64N {
}
}

/// Convert a TAI64N timestamp to two integers
fn tai64_to_ints(tai64n: &TAI64N) -> (u64, u32) {
/// Convert a Timestamp timestamp to two integers
fn tai64_to_ints(tai64n: &Timestamp) -> (u64, u32) {
let encoded = tai64n.to_bytes();
let secs = u64::from_le_bytes(encoded[..8].try_into().unwrap());
let nanos = u32::from_le_bytes(encoded[8..].try_into().unwrap());
Expand Down
17 changes: 5 additions & 12 deletions rust/src/builtins/uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,16 @@
pub use uuid::Uuid;

use crate::{
decoder::{Decodable, Decoder},
encoder::Encoder,
error::Error,
field::{self, WireType},
message::Message,
decoder::{DecodeRef, Decoder},
field, Encoder, Error, Message,
};
use core::convert::TryInto;

impl Message for Uuid {
fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
let mut bytes = bytes.as_ref();
let mut decoder = Decoder::new();
fn decode(decoder: &mut Decoder, mut input: &[u8]) -> Result<Self, Error> {
let bytes: &[u8] = decoder.decode_ref(0, &mut input)?;

decoder.decode_expected_header(&mut bytes, 0, WireType::String)?;
let uuid_bytes = decoder.decode_bytes(&mut bytes)?;

uuid_bytes
bytes
.try_into()
.map(Uuid::from_bytes)
.map_err(|_| Error::Builtin)
Expand Down
Loading

0 comments on commit f126e46

Please sign in to comment.