Skip to content

Commit

Permalink
Implement an UperWriter for the (for now) very basic Writer trait #11 #6
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 27, 2020
1 parent c4da2ce commit c1168d8
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 2 deletions.
18 changes: 16 additions & 2 deletions src/io/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::iter;
#[derive(Debug, Default)]
pub struct BitBuffer {
buffer: Vec<u8>,
write_position: usize,
read_position: usize,
pub(crate) write_position: usize,
pub(crate) read_position: usize,
}

impl BitBuffer {
Expand Down Expand Up @@ -62,6 +62,20 @@ impl BitBuffer {
pub fn byte_len(&self) -> usize {
self.buffer.len()
}

/// Changes the write-position to the given position for the closure call.
/// Restores the original write position after the call.
///
/// # Panics
/// Positions beyond the current buffer length will result in panics.
pub fn with_write_position_at<T, F: Fn(&mut Self) -> T>(&mut self, position: usize, f: F) -> T {
assert!(position <= self.buffer.len());
let before = self.write_position;
self.write_position = position;
let result = f(self);
self.write_position = before;
result
}
}

fn bit_string_copy(
Expand Down
2 changes: 2 additions & 0 deletions src/syn/io/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod println;
mod uper;

pub use println::*;
pub use uper::*;
75 changes: 75 additions & 0 deletions src/syn/io/uper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::io::buffer::BitBuffer;
use crate::io::uper::Error as UperError;
use crate::io::uper::Writer as _;
use crate::prelude::*;
use std::fmt::{Display, Formatter};

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

impl UperWriter {
pub fn byte_content(&self) -> &[u8] {
self.buffer.content()
}

pub const fn bit_len(&self) -> usize {
self.buffer.bit_len()
}
}

impl Writer for UperWriter {
type Error = UperError;

fn write_sequence<C: sequence::Constraint, F: Fn(&mut Self) -> Result<(), Self::Error>>(
&mut self,
f: F,
) -> Result<(), Self::Error> {
// in UPER the optional flag for all OPTIONAL values is 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 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);
self.buffer.write_bit(false);
}
f(self)?;
assert_eq!(before, self.optional_positions.len());
Ok(())
}

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(value) = value {
T::write_value(self, value)
} else {
Ok(())
}
}

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

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

fn write_utf8string<C: utf8string::Constraint>(
&mut self,
value: &str,
) -> Result<(), Self::Error> {
self.buffer.write_utf8_string(value)
}
}
22 changes: 22 additions & 0 deletions tests/basic_proc_macro_attribute.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(unused)]

use asn1rs::syn::io::UperWriter;
use asn1rs_macros::asn;

#[asn(sequence)]
Expand All @@ -24,3 +25,24 @@ fn test_compiles() {
string: String::from("where is the content"),
};
}

#[test]
fn test_serialize_with_uper() {
let p = Potato {
size: 123,
size2: 1234,
size3: 128,
string: String::from("where is the content"),
};
let mut uper = UperWriter::default();
uper.write(&p).unwrap();
assert_eq!(
&[
// 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
],
uper.byte_content()
);
assert_eq!(26 * 8 + 7, uper.bit_len());
}

0 comments on commit c1168d8

Please sign in to comment.