Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d75d2c5
Option with defining groups
Artemkaaas Feb 8, 2023
31cf6d5
Added stubs for missing groups + code refactoring
Artemkaaas Feb 9, 2023
72a54c1
Added group constructors and example of to_string/to_bytes
Artemkaaas Feb 9, 2023
36b5b1c
Simplified group definition
Artemkaaas Feb 9, 2023
02f70a6
Refactored parser util
Artemkaaas Feb 9, 2023
0c9caaf
Added uniffi bindings
Artemkaaas Feb 10, 2023
95a364e
Added stubs for primitives parsers
Artemkaaas Feb 10, 2023
a72e123
Refactored groups definition
Artemkaaas Feb 10, 2023
69eaddf
Updated parside to use the latest cesride
Artemkaaas Feb 21, 2023
91f692b
Updated cesride version
Artemkaaas Feb 27, 2023
c80bad4
Exclude Uniffi in favor of third crate
Artemkaaas Feb 27, 2023
f77d21e
Removed exporting of cesride primitives
Artemkaaas Feb 28, 2023
9788a84
Merge remote-tracking branch 'origin/main' into initial-implementation
Artemkaaas Feb 28, 2023
f5796f6
Update for moved *_size in cesride
DmitryKuzmenko Mar 3, 2023
5831ff8
Cargo fmt
DmitryKuzmenko Mar 3, 2023
716d53c
Clippy fixes
DmitryKuzmenko Mar 3, 2023
0d8753f
Update for new full_size functions. Fix-ups for b64/b2
DmitryKuzmenko Mar 3, 2023
9983e44
Handle empty stream in nom group parser
DmitryKuzmenko Mar 4, 2023
eb0c3df
Support anyhow error
DmitryKuzmenko Mar 17, 2023
f3c6c59
Formatting
DmitryKuzmenko Mar 17, 2023
96cdd30
Bump cesride version
DmitryKuzmenko Mar 28, 2023
43cf74d
Implemented full_size for groups
DmitryKuzmenko Mar 28, 2023
72cb1d8
Use memcpy copying in qb*
DmitryKuzmenko Mar 28, 2023
b20d7c4
Updated nom version + added more tests for groups parsing
Artemkaaas Apr 17, 2023
224aa52
[WIP] parside wasm
DmitryKuzmenko Mar 27, 2023
76d88e1
tmp
DmitryKuzmenko Mar 28, 2023
6f78fe3
tmp2
DmitryKuzmenko Apr 12, 2023
e36bd9b
Added wasm binding for groups and messages
Artemkaaas Apr 14, 2023
351ec38
Added attached material quadlets
Artemkaaas Apr 14, 2023
fcd28be
Refactoring and improvements
Artemkaaas Apr 17, 2023
1de7d97
Added web sample
Artemkaaas Apr 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
/cargo/*/Cargo.lock
/*.profraw
.idea
.vscode
lcov.info
14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ edition = "2021"
description = "Parser for Composable Event Streaming Representation (CESR)"
license = "Apache-2.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# cesride = { version = "0.1.3", path = "../cesride" }
cesride = "0.1.3"
cesride = { git = "https://github.com/DSRCorporation/cesride.git", branch = "fix/wasm-readme" }
nom = "~7.1"
num-derive = "~0.3"
num-traits = "~0.2"
rmp-serde = "~1"
serde = { version = "~1", features = ["derive"] }
serde_json = { version = "~1", features = ["preserve_order"] }
serde_cbor = "~0.11"
thiserror = "~1"
anyhow = "~1"
18 changes: 1 addition & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
python:
@cp Cargo.toml cargo/$@/
@echo "pyo3 = { version = \"0.18.0\", features = [\"abi3\", \"extension-module\"] }" >> cargo/$@/Cargo.toml
@echo >> cargo/$@/Cargo.toml
@cat cargo/$@/Cargo.toml.tail >> cargo/$@/Cargo.toml
@cd cargo/$@ && cargo build --release --target-dir ../../target/$@
@mv target/$@/release/libparside.dylib target/$@/release/parside.so

python-shell:
@cd target/python/release/ && python3

rust:
@cargo build --release

libs: rust python

clean:
cargo clean

Expand All @@ -22,9 +6,9 @@ fix:
cargo fmt

preflight:
cargo audit
cargo fmt --check
cargo clippy -- -D warnings
cargo build --release
cargo test --release
cargo audit
cargo tarpaulin
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,66 @@
[![parside](https://github.com/WebOfTrust/parside/actions/workflows/test.yml/badge.svg)](https://github.com/WebOfTrust/parside/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/WebOfTrust/parside/branch/main/graph/badge.svg?token=L8K7H1XXQS)](https://codecov.io/gh/WebOfTrust/parside)

Parser for use with Composable Event Streaming Representation (CESR).
Parser library for Composable Event Streaming Representation (CESR).

This library is **currently under construction**.

## Example

Parse stream containing multiple messages:

```
use cesride::{CesrGroup, Message, MessageList};

let stream = br#"{"v":"12b_","t":"icp"}-CABBD8-gMSJ6K1PQ7_gG5ZJn2NkHQJgdkiNrTBz_FWWS_cC0BDc1i44ZX0jaIHh5oNDx-TITbPnI6VEn2nKlqPwkkTF452X7XxYh80tolDpReYwZpnD8TF4Or2v3CpSCikyt6EG{"v":"81b_","t":"tcp"}-AABAABg3q8uNg1A2jhEAdbKGf-QupQhNnmZQx3zIyPLWBe6qqLT5ynytivf9EwJhxyhy87a0x2cezDdil4SsM2xxs0Orest"#;
let (rest, message_list) = MessageList::from_stream_bytes(stream)?;
println!("Rest bytes: {:?}", rest);

for message in message_list.messages {
match message {
Message::Custom { value } => {
println!("Handle custom payload {:?}", value)
},
Message::Group { value } => {
match value {
CesrGroup::ControllerIdxSigsVariant { value } => println!("Handle ControllerIdxSigsVariant {:?}", value),
CesrGroup::WitnessIdxSigsVariant { value } => println!("Handle WitnessIdxSigsVariant {:?}", value),
CesrGroup::NonTransReceiptCouplesVariant { value } => println!("Handle NonTransReceiptCouplesVariant {:?}", value),
CesrGroup::TransReceiptQuadruplesVariant { value } => println!("Handle TransReceiptQuadruplesVariant {:?}", value),
CesrGroup::TransIdxSigGroupsVariant { value } => println!("Handle TransIdxSigGroupsVariant {:?}", value),
CesrGroup::TransLastIdxSigGroupsVariant { value } => println!("Handle TransLastIdxSigGroupsVariant {:?}", value),
CesrGroup::FirstSeenReplayCouplesVariant { value } => println!("Handle FirstSeenReplayCouplesVariant {:?}", value),
CesrGroup::SealSourceCouplesVariant { value } => println!("Handle SealSourceCouplesVariant {:?}", value),
CesrGroup::AttachedMaterialQuadletsVariant { value } => println!("Handle AttachedMaterialQuadletsVariant {:?}", value),
CesrGroup::SadPathSigGroupVariant { value } => println!("Handle SadPathSigGroupVariant {:?}", value),
CesrGroup::SadPathSigVariant { value } => println!("Handle SadPathSigVariant {:?}", value),
CesrGroup::PathedMaterialQuadletsVariant { value } => println!("Handle PathedMaterialQuadletsVariant {:?}", value),
}
}
}
}
```

Parse single message from stream:
```
use cesride::{CesrGroup, Message, MessageList};

let stream = br#"{"v":"12b_","t":"icp"}-CABBD8-gMSJ6K1PQ7_gG5ZJn2NkHQJgdkiNrTBz_FWWS_cC0BDc1i44ZX0jaIHh5oNDx-TITbPnI6VEn2nKlqPwkkTF452X7XxYh80tolDpReYwZpnD8TF4Or2v3CpSCikyt6EG{"v":"81b_","t":"tcp"}-AABAABg3q8uNg1A2jhEAdbKGf-QupQhNnmZQx3zIyPLWBe6qqLT5ynytivf9EwJhxyhy87a0x2cezDdil4SsM2xxs0Orest"#;
let (rest, message) = Message::from_stream_bytes(stream).unwrap();
println!("Rest bytes: {:?}", rest);

match message {
Message::Custom { value } => {
println!("Handle custom payload {:?}", value)
},
Message::Group { value } => {
match value {
CesrGroup::ControllerIdxSigsVariant { value } => println!("Handle ControllerIdxSigsVariant {:?}", value),
_ => println!("Handle Group"),
}
}
}
```

## Community

Expand Down
37 changes: 37 additions & 0 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use nom::error::ErrorKind;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
pub enum ParsideError {
#[error("Payload deserialize error: {0}")]
PayloadDeserializeError(String),

#[error("Nom error")]
StreamDeserializationError(ErrorKind),

#[error("Empty bytes stream passed for parsing")]
EmptyBytesStream,

#[error("Requested variant does not exists")]
NotExist,

#[error("Unexpected variant")]
Unexpected(String),

#[error("Common error")]
Common(String),
}

impl<E> From<nom::Err<E>> for ParsideError {
fn from(_: nom::Err<E>) -> ParsideError {
ParsideError::StreamDeserializationError(ErrorKind::IsNot)
}
}

impl From<anyhow::Error> for ParsideError {
fn from(err: anyhow::Error) -> ParsideError {
ParsideError::Common(err.to_string())
}
}

pub type ParsideResult<T> = Result<T, ParsideError>;
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
pub mod error;
pub mod message;
mod utils;

pub use message::{CesrGroup, CustomPayload, Group, Message, MessageList};
39 changes: 39 additions & 0 deletions src/message/cold_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;

use crate::error::{ParsideError, ParsideResult};

/// Cold code defining the serialization format: https://weboftrust.github.io/ietf-cesr/draft-ssmith-cesr.html#section-3.6
#[repr(u8)]
#[derive(FromPrimitive, ToPrimitive, Debug, Clone)]
pub(crate) enum ColdCode {
// not taken
Free = 0b000,
// CountCode Base64
CtB64 = 0b001,
// OpCode Base64
OpB64 = 0b010,
// JSON Map Event Start
Json = 0b011,
// MGPK Fixed Map Event Start
MGPK1 = 0b100,
// CBOR Map Event Start
Cbor = 0b101,
// MGPK Big 16 or 32 Map Event Start
MGPK2 = 0b110,
// CountCode or OpCode Base2
CtOpB2 = 0b111,
}

impl TryFrom<u8> for ColdCode {
type Error = ParsideError;

fn try_from(byte: u8) -> ParsideResult<Self> {
let tritet = byte >> 5;
FromPrimitive::from_u8(tritet).ok_or_else(|| {
ParsideError::PayloadDeserializeError(
"Unable to parse Message cold start code".to_string(),
)
})
}
}
53 changes: 53 additions & 0 deletions src/message/custom_payload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use rmp_serde as serde_mgpk;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde_json::Value as JsonValue;
use std::io::Cursor;

use crate::error::{ParsideError, ParsideResult};

/// Datastructures representing custom payload
#[derive(Debug, Clone)]
pub struct CustomPayload {
pub value: JsonValue,
}

impl CustomPayload {
/// Convert custom payload to specific type
pub fn to_typed_message<D>(&self) -> ParsideResult<D>
where
D: DeserializeOwned,
{
serde_json::from_value::<D>(self.value.to_owned())
.map_err(|err| ParsideError::PayloadDeserializeError(err.to_string()))
}

/// Parse custom payload from JSON representation
pub(crate) fn from_json_stream(s: &[u8]) -> ParsideResult<(&[u8], CustomPayload)> {
let mut stream = serde_json::Deserializer::from_slice(s).into_iter::<JsonValue>();
match stream.next() {
Some(Ok(value)) => Ok((&s[stream.byte_offset()..], CustomPayload { value })),
Some(Err(err)) => Err(ParsideError::PayloadDeserializeError(err.to_string())),
None => Err(ParsideError::PayloadDeserializeError("End of stream".to_string())),
}
}

/// Parse custom payload from CBOR representation
pub(crate) fn from_cbor_stream(s: &[u8]) -> ParsideResult<(&[u8], CustomPayload)> {
let mut stream = serde_cbor::Deserializer::from_slice(s).into_iter::<JsonValue>();
match stream.next() {
Some(Ok(value)) => Ok((&s[stream.byte_offset()..], CustomPayload { value })),
Some(Err(err)) => Err(ParsideError::PayloadDeserializeError(err.to_string())),
None => Err(ParsideError::PayloadDeserializeError("End of stream".to_string())),
}
}

/// Parse custom payload from MessagePack representation
pub(crate) fn from_mgpk_stream(s: &[u8]) -> ParsideResult<(&[u8], CustomPayload)> {
let mut deser = serde_mgpk::Deserializer::new(Cursor::new(s));
match Deserialize::deserialize(&mut deser) {
Ok(value) => Ok((&s[deser.get_ref().position() as usize..], CustomPayload { value })),
Err(err) => Err(ParsideError::PayloadDeserializeError(err.to_string())),
}
}
}
105 changes: 105 additions & 0 deletions src/message/groups/attached_material_quadlets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::error::ParsideResult;
use crate::message::cold_code::ColdCode;
use crate::message::{Group, GroupItem};
use crate::{nomify, CesrGroup};
use cesride::counter::Codex;
use cesride::Counter;
use nom::multi::many0;

#[derive(Debug, Clone, Default)]
pub struct AttachedMaterialQuadlets {
pub value: Vec<CesrGroup>,
}

impl Group<CesrGroup> for AttachedMaterialQuadlets {
const CODE: &'static str = Codex::AttachedMaterialQuadlets;

fn new(value: Vec<CesrGroup>) -> Self {
Self { value }
}

fn value(&self) -> &Vec<CesrGroup> {
&self.value
}
}

impl AttachedMaterialQuadlets {
pub(crate) fn from_stream_bytes<'a>(
bytes: &'a [u8],
_counter: &Counter,
_cold_code: &ColdCode,
) -> ParsideResult<(&'a [u8], AttachedMaterialQuadlets)> {
let (rest, body) = many0(nomify!(CesrGroup::from_stream_bytes))(bytes)?;
Ok((rest, AttachedMaterialQuadlets { value: body }))
}
}

impl GroupItem for CesrGroup {
fn qb64(&self) -> ParsideResult<String> {
match self {
CesrGroup::ControllerIdxSigsVariant { value } => value.qb64(),
CesrGroup::WitnessIdxSigsVariant { value } => value.qb64(),
CesrGroup::NonTransReceiptCouplesVariant { value } => value.qb64(),
CesrGroup::TransReceiptQuadruplesVariant { value } => value.qb64(),
CesrGroup::TransIdxSigGroupsVariant { value } => value.qb64(),
CesrGroup::TransLastIdxSigGroupsVariant { value } => value.qb64(),
CesrGroup::FirstSeenReplayCouplesVariant { value } => value.qb64(),
CesrGroup::SealSourceCouplesVariant { value } => value.qb64(),
CesrGroup::AttachedMaterialQuadletsVariant { value } => value.qb64(),
CesrGroup::SadPathSigGroupVariant { value } => value.qb64(),
CesrGroup::SadPathSigVariant { value } => value.qb64(),
CesrGroup::PathedMaterialQuadletsVariant { value } => value.qb64(),
}
}

fn qb64b(&self) -> ParsideResult<Vec<u8>> {
match self {
CesrGroup::ControllerIdxSigsVariant { value } => value.qb64b(),
CesrGroup::WitnessIdxSigsVariant { value } => value.qb64b(),
CesrGroup::NonTransReceiptCouplesVariant { value } => value.qb64b(),
CesrGroup::TransReceiptQuadruplesVariant { value } => value.qb64b(),
CesrGroup::TransIdxSigGroupsVariant { value } => value.qb64b(),
CesrGroup::TransLastIdxSigGroupsVariant { value } => value.qb64b(),
CesrGroup::FirstSeenReplayCouplesVariant { value } => value.qb64b(),
CesrGroup::SealSourceCouplesVariant { value } => value.qb64b(),
CesrGroup::AttachedMaterialQuadletsVariant { value } => value.qb64b(),
CesrGroup::SadPathSigGroupVariant { value } => value.qb64b(),
CesrGroup::SadPathSigVariant { value } => value.qb64b(),
CesrGroup::PathedMaterialQuadletsVariant { value } => value.qb64b(),
}
}

fn qb2(&self) -> ParsideResult<Vec<u8>> {
match self {
CesrGroup::ControllerIdxSigsVariant { value } => value.qb2(),
CesrGroup::WitnessIdxSigsVariant { value } => value.qb2(),
CesrGroup::NonTransReceiptCouplesVariant { value } => value.qb2(),
CesrGroup::TransReceiptQuadruplesVariant { value } => value.qb2(),
CesrGroup::TransIdxSigGroupsVariant { value } => value.qb2(),
CesrGroup::TransLastIdxSigGroupsVariant { value } => value.qb2(),
CesrGroup::FirstSeenReplayCouplesVariant { value } => value.qb2(),
CesrGroup::SealSourceCouplesVariant { value } => value.qb2(),
CesrGroup::AttachedMaterialQuadletsVariant { value } => value.qb2(),
CesrGroup::SadPathSigGroupVariant { value } => value.qb2(),
CesrGroup::SadPathSigVariant { value } => value.qb2(),
CesrGroup::PathedMaterialQuadletsVariant { value } => value.qb2(),
}
}

fn full_size(&self) -> ParsideResult<u32> {
match self {
Self::ControllerIdxSigsVariant { value } => value.full_size(),
Self::WitnessIdxSigsVariant { value } => value.full_size(),
Self::NonTransReceiptCouplesVariant { value } => value.full_size(),
Self::TransReceiptQuadruplesVariant { value } => value.full_size(),
Self::TransIdxSigGroupsVariant { value } => value.full_size(),
Self::TransLastIdxSigGroupsVariant { value } => value.full_size(),
Self::FirstSeenReplayCouplesVariant { value } => value.full_size(),
Self::SealSourceCouplesVariant { value } => value.full_size(),
Self::AttachedMaterialQuadletsVariant { value } => value.full_size(),
Self::SadPathSigGroupVariant { value } => value.full_size(),
Self::SadPathSigVariant { value } => value.full_size(),
Self::PathedMaterialQuadletsVariant { value } => value.full_size(),
}
}
}
Loading