Skip to content

Commit

Permalink
Support SEQUENCE OF in fields #11
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 30, 2020
1 parent b2679ef commit 075e5d9
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 51 deletions.
6 changes: 6 additions & 0 deletions asn1rs-macros/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ fn parse_type<'a>(input: &'a ParseBuffer<'a>) -> syn::Result<Type> {
let inner = parse_type(&content)?;
Ok(Type::Optional(Box::new(inner)))
}
"sequence_of" => {
let content;
parenthesized!(content in input);
let inner = parse_type(&content)?;
Ok(Type::SequenceOf(Box::new(inner)))
}
r#type => Err(input.error(format!("Unexpected attribute: `{}`", r#type))),
}
}
6 changes: 6 additions & 0 deletions src/io/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Error {
InsufficientDataInSourceBuffer,
InvalidChoiceIndex(usize, usize),
ValueNotInRange(i64, i64, i64),
SizeNotInRange(usize, usize, usize),
EndOfStream,
}

Expand Down Expand Up @@ -45,6 +46,11 @@ impl std::fmt::Display for Error {
"The value {} is not within the inclusive range of {} and {}",
value, min, max
),
Error::SizeNotInRange(size, min, max) => write!(
f,
"The size {} is not within the inclusive range of {} and {}",
size, min, max
),
Error::EndOfStream => write!(
f,
"Can no longer read or write any bytes from the underlying dataset"
Expand Down
21 changes: 21 additions & 0 deletions src/syn/io/println.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ impl Writer for PrintlnWriter {
self.with_increased_indentation(|w| f(w))
}

fn write_sequence_of<C: sequenceof::Constraint, T: WritableType>(
&mut self,
slice: &[T::Type],
) -> Result<(), Self::Error> {
self.indented_println(format!(
"Writing sequence-of ({}..{})",
C::MIN
.map(|v| format!("{}", v))
.unwrap_or_else(|| String::from("MIN")),
C::MAX
.map(|v| format!("{}", v))
.unwrap_or_else(|| String::from("MAX")),
));
self.with_increased_indentation(|w| {
for value in slice {
T::write_value(w, value)?;
}
Ok(())
})
}

fn write_enumerated<C: enumerated::Constraint>(
&mut self,
enumerated: &C,
Expand Down
202 changes: 153 additions & 49 deletions src/syn/io/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,37 @@ use crate::io::uper::Reader as _UperReader;
use crate::io::uper::Writer as _UperWriter;
use crate::prelude::*;

#[derive(Default)]
pub struct ScopeStack<T> {
scopes: Vec<Vec<T>>,
scope: Vec<T>,
}

impl<T> ScopeStack<T> {
pub fn current_mut(&mut self) -> &mut Vec<T> {
&mut self.scope
}

pub fn stash(&mut self) {
self.push(Vec::default())
}

pub fn push(&mut self, mut scope: Vec<T>) {
std::mem::swap(&mut scope, &mut self.scope);
self.scopes.push(scope);
}

pub fn pop(&mut self) -> Vec<T> {
let mut scope = self.scopes.pop().unwrap_or_default();
std::mem::swap(&mut scope, &mut self.scope);
scope
}
}

#[derive(Default)]
pub struct UperWriter {
buffer: BitBuffer,
optional_positions: Vec<usize>,
scope: ScopeStack<usize>,
}

impl UperWriter {
Expand All @@ -28,6 +55,23 @@ impl UperWriter {
let bytes = self.into_bytes_vec();
UperReader::from_bits(bytes, bits)
}

pub fn scope_pushed<R, F: Fn(&mut Self) -> R>(
&mut self,
scope: Vec<usize>,
f: F,
) -> (R, Vec<usize>) {
self.scope.push(scope);
let result = f(self);
(result, self.scope.pop())
}

pub fn scope_stashed<R, F: Fn(&mut Self) -> R>(&mut self, f: F) -> R {
self.scope.stash();
let result = f(self);
self.scope.pop();
result
}
}

impl Writer for UperWriter {
Expand All @@ -40,22 +84,41 @@ impl Writer for UperWriter {
// 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();
let mut list = Vec::default();
let write_pos = self.buffer.write_position;
for i in (0..C::OPTIONAL_FIELDS).rev() {
// insert in reverse order so that a simple pop() in `write_opt` retrieves
// the relevant position
self.optional_positions.push(write_pos + i);
list.push(write_pos + i);
if let Err(e) = self.buffer.write_bit(false) {
self.buffer.write_position = write_pos; // undo write_bits
return Err(e);
}
}
f(self)?;
assert_eq!(before, self.optional_positions.len());
let (result, scope) = self.scope_pushed(list, f);
result?; // first error on this before throwing non-informative assert errors
assert!(scope.is_empty());
Ok(())
}

fn write_sequence_of<C: sequenceof::Constraint, T: WritableType>(
&mut self,
slice: &[T::Type],
) -> Result<(), Self::Error> {
let min = C::MIN.unwrap_or(0);
let max = C::MAX.unwrap_or(std::usize::MAX);
if slice.len() < min || slice.len() > max {
return Err(UperError::SizeNotInRange(slice.len(), min, max));
}
self.scope_stashed(|w| {
w.buffer.write_length_determinant(slice.len() - min)?; // TODO untested for MIN != 0
for value in slice {
T::write_value(w, value)?;
}
Ok(())
})
}

fn write_enumerated<C: enumerated::Constraint>(
&mut self,
enumerated: &C,
Expand All @@ -74,28 +137,34 @@ impl Writer for UperWriter {
}

fn write_choice<C: choice::Constraint>(&mut self, choice: &C) -> Result<(), Self::Error> {
if C::EXTENSIBLE {
self.buffer.write_choice_index_extensible(
choice.to_choice_index() as u64,
C::STD_VARIANT_COUNT as u64,
)?;
} else {
self.buffer
.write_choice_index(choice.to_choice_index() as u64, C::STD_VARIANT_COUNT as u64)?;
}
choice.write_content(self)
self.scope_stashed(|w| {
if C::EXTENSIBLE {
w.buffer.write_choice_index_extensible(
choice.to_choice_index() as u64,
C::STD_VARIANT_COUNT as u64,
)?;
} else {
w.buffer.write_choice_index(
choice.to_choice_index() as u64,
C::STD_VARIANT_COUNT as u64,
)?;
}
choice.write_content(w)
})
}

fn write_opt<T: WritableType>(
&mut self,
value: Option<&<T as WritableType>::Type>,
) -> Result<(), Self::Error> {
self.buffer
.with_write_position_at(self.optional_positions.pop().unwrap(), |buffer| {
buffer.write_bit(value.is_some())
})?;
if let Some(position) = self.scope.current_mut().pop() {
self.buffer
.with_write_position_at(position, |buffer| buffer.write_bit(value.is_some()))?;
} else {
self.buffer.write_bit(value.is_some())?;
}
if let Some(value) = value {
T::write_value(self, value)
self.scope_stashed(|w| T::write_value(w, value))
} else {
Ok(())
}
Expand Down Expand Up @@ -127,20 +196,37 @@ impl Writer for UperWriter {

pub struct UperReader {
buffer: BitBuffer,
optionals: Vec<bool>,
scope: ScopeStack<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(),
scope: Default::default(),
}
}

pub fn bits_remaining(&self) -> usize {
self.buffer.write_position - self.buffer.read_position
}

pub fn scope_pushed<R, F: Fn(&mut Self) -> R>(
&mut self,
scope: Vec<bool>,
f: F,
) -> (R, Vec<bool>) {
self.scope.push(scope);
let result = f(self);
(result, self.scope.pop())
}

pub fn scope_stashed<R, F: Fn(&mut Self) -> R>(&mut self, f: F) -> R {
self.scope.stash();
let result = f(self);
self.scope.pop();
result
}
}

impl Reader for UperReader {
Expand All @@ -157,21 +243,32 @@ impl Reader for UperReader {
// 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);
let mut optionals = vec![false; C::OPTIONAL_FIELDS];
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);
}
}
optionals[i] = self.buffer.read_bit()?;
}
let result = f(self);
assert_eq!(position, self.optionals.len());
result
let (result, scope) = self.scope_pushed(optionals, f);
let result = result?; // first error on this before throwing non-informative assert errors
assert!(scope.is_empty());
Ok(result)
}

fn read_sequence_of<C: sequenceof::Constraint, T: ReadableType>(
&mut self,
) -> Result<Vec<T::Type>, Self::Error> {
let min = C::MIN.unwrap_or(0);
let max = C::MAX.unwrap_or(std::usize::MAX);
let len = self.buffer.read_length_determinant()? + min; // TODO untested for MIN != 0
if len > max {
return Err(UperError::SizeNotInRange(len, min, max));
}
self.scope_stashed(|w| {
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
vec.push(T::read_value(w)?);
}
Ok(vec)
})
}

fn read_enumerated<C: enumerated::Constraint>(&mut self) -> Result<C, Self::Error> {
Expand All @@ -191,26 +288,33 @@ impl Reader for UperReader {
}

fn read_choice<C: choice::Constraint>(&mut self) -> Result<C, Self::Error> {
if C::EXTENSIBLE {
self.buffer
.read_choice_index_extensible(C::STD_VARIANT_COUNT as u64)
.map(|v| v as usize)
} else {
self.buffer
.read_choice_index(C::STD_VARIANT_COUNT as u64)
.map(|v| v as usize)
}
.and_then(|index| {
C::read_content(index, self)?
.ok_or_else(|| UperError::InvalidChoiceIndex(index, C::VARIANT_COUNT))
self.scope_stashed(|w| {
if C::EXTENSIBLE {
w.buffer
.read_choice_index_extensible(C::STD_VARIANT_COUNT as u64)
.map(|v| v as usize)
} else {
w.buffer
.read_choice_index(C::STD_VARIANT_COUNT as u64)
.map(|v| v as usize)
}
.and_then(|index| {
C::read_content(index, w)?
.ok_or_else(|| UperError::InvalidChoiceIndex(index, C::VARIANT_COUNT))
})
})
}

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)
let value = if let Some(pre_fetched) = self.scope.current_mut().pop() {
pre_fetched
} else {
self.buffer.read_bit()?
};
if value {
self.scope_stashed(T::read_value).map(Some)
} else {
Ok(None)
}
Expand Down
11 changes: 11 additions & 0 deletions src/syn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod numbers;
pub mod octetstring;
pub mod optional;
pub mod sequence;
pub mod sequenceof;
pub mod utf8string;

pub use choice::Choice;
Expand All @@ -16,6 +17,7 @@ pub use enumerated::Enumerated;
pub use numbers::Integer;
pub use octetstring::OctetString;
pub use sequence::Sequence;
pub use sequenceof::SequenceOf;
pub use utf8string::Utf8String;

pub trait Reader {
Expand All @@ -37,6 +39,10 @@ pub trait Reader {
f: F,
) -> Result<S, Self::Error>;

fn read_sequence_of<C: sequenceof::Constraint, T: ReadableType>(
&mut self,
) -> Result<Vec<T::Type>, Self::Error>;

fn read_enumerated<C: enumerated::Constraint>(&mut self) -> Result<C, Self::Error>;

fn read_choice<C: choice::Constraint>(&mut self) -> Result<C, Self::Error>;
Expand Down Expand Up @@ -89,6 +95,11 @@ pub trait Writer {
f: F,
) -> Result<(), Self::Error>;

fn write_sequence_of<C: sequenceof::Constraint, T: WritableType>(
&mut self,
slice: &[T::Type],
) -> Result<(), Self::Error>;

fn write_enumerated<C: enumerated::Constraint>(
&mut self,
enumerated: &C,
Expand Down
Loading

0 comments on commit 075e5d9

Please sign in to comment.