Skip to content

Commit

Permalink
Implement an UperReader for the (for now) very basic Reader trait #11 #6
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 27, 2020
1 parent c1168d8 commit c91ab54
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
71 changes: 70 additions & 1 deletion src/syn/io/uper.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::io::buffer::BitBuffer;
use crate::io::uper::Error as UperError;
use crate::io::uper::Reader as _;
use crate::io::uper::Writer as _;
use crate::prelude::*;
use std::fmt::{Display, Formatter};
Expand Down Expand Up @@ -27,7 +28,7 @@ impl Writer for UperWriter {
&mut self,
f: F,
) -> Result<(), Self::Error> {
// in UPER the optional flag for all OPTIONAL values is written before any field
// In UPER the optional flag for all OPTIONAL values are written before any field
// value is written. This reserves the bits, so that on a later call of `write_opt`
// the value can be set to the actual state.
let before = self.optional_positions.len();
Expand Down Expand Up @@ -73,3 +74,71 @@ impl Writer for UperWriter {
self.buffer.write_utf8_string(value)
}
}

pub struct UperReader {
buffer: BitBuffer,
optionals: Vec<bool>,
}

impl UperReader {
pub fn from_bits<I: Into<Vec<u8>>>(bytes: I, bit_len: usize) -> Self {
Self {
buffer: BitBuffer::from_bits(bytes.into(), bit_len),
optionals: Vec::default(),
}
}
}

impl Reader for UperReader {
type Error = UperError;

fn read_sequence<
C: sequence::Constraint,
S: Sized,
F: Fn(&mut Self) -> Result<S, Self::Error>,
>(
&mut self,
f: F,
) -> Result<S, Self::Error> {
// In UPER the optional flag for all OPTIONAL values are written before any field
// value is written. This loads those bits, so that on a later call of `read_opt` can
// retrieve them by a simple call of `pop` on the optionals buffer
let position = self.optionals.len();
self.optionals.resize(position + C::OPTIONAL_FIELDS, false);
for i in (0..C::OPTIONAL_FIELDS).rev() {
self.optionals[position + i] = match self.buffer.read_bit() {
Ok(bit) => bit,
Err(e) => {
// need to remove eagerly added values
self.optionals.resize(position, false);
return Err(e);
}
}
}
let result = f(self);
assert_eq!(position, self.optionals.len());
result
}

fn read_opt<T: ReadableType>(
&mut self,
) -> Result<Option<<T as ReadableType>::Type>, Self::Error> {
if self.optionals.pop().unwrap() {
T::read_value(self).map(Some)
} else {
Ok(None)
}
}

fn read_int(&mut self, range: (i64, i64)) -> Result<i64, Self::Error> {
self.buffer.read_int(range)
}

fn read_int_max(&mut self) -> Result<u64, Self::Error> {
self.buffer.read_int_max()
}

fn read_utf8string<C: utf8string::Constraint>(&mut self) -> Result<String, Self::Error> {
self.buffer.read_utf8_string()
}
}
26 changes: 24 additions & 2 deletions tests/basic_proc_macro_attribute.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![allow(unused)]

use asn1rs::syn::io::UperWriter;
use asn1rs::syn::io::{UperReader, UperWriter};
use asn1rs_macros::asn;

#[asn(sequence)]
#[derive(Default)]
#[derive(Debug, Default, PartialOrd, PartialEq)]
pub struct Potato {
#[asn(integer)]
size: u64,
Expand Down Expand Up @@ -46,3 +46,25 @@ fn test_serialize_with_uper() {
);
assert_eq!(26 * 8 + 7, uper.bit_len());
}

#[test]
fn test_deserialize_with_uper() {
let mut uper = UperReader::from_bits(
vec![
// https://asn1.io/asn1playground/
0x01, 0x7B, 0x02, 0x04, 0xD2, 0xE8, 0x28, 0xEE, 0xD0, 0xCA, 0xE4, 0xCA, 0x40, 0xD2,
0xE6, 0x40, 0xE8, 0xD0, 0xCA, 0x40, 0xC6, 0xDE, 0xDC, 0xE8, 0xCA, 0xDC, 0xE8,
],
26 * 8 + 7,
);
let p = uper.read::<Potato>().unwrap();
assert_eq!(
Potato {
size: 123,
size2: 1234,
size3: 128,
string: String::from("where is the content"),
},
p
);
}

0 comments on commit c91ab54

Please sign in to comment.