Skip to content

Commit

Permalink
Parse INTEGER types without range as INTEGER(0..MAX) #6
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 14, 2020
1 parent ee9a214 commit e367718
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 37 deletions.
88 changes: 51 additions & 37 deletions asn1rs-model/src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use backtrace::Backtrace;
use std::convert::TryFrom;
use std::error::Error as StdError;
use std::fmt::{Debug, Display, Formatter};
use std::iter::Peekable;
use std::vec::IntoIter;

macro_rules! loop_ctrl_separator {
Expand Down Expand Up @@ -234,7 +235,7 @@ impl<T> Default for Model<T> {
impl Model<Asn> {
pub fn try_from(value: Vec<Token>) -> Result<Self, Error> {
let mut model = Model::default();
let mut iter = value.into_iter();
let mut iter = value.into_iter().peekable();

model.name = Self::read_name(&mut iter)?;
Self::skip_until_after_text_ignore_ascii_case(&mut iter, "BEGIN")?;
Expand All @@ -257,14 +258,14 @@ impl Model<Asn> {
Err(Error::unexpected_end_of_stream())
}

fn read_name(iter: &mut IntoIter<Token>) -> Result<String, Error> {
fn read_name(iter: &mut Peekable<IntoIter<Token>>) -> Result<String, Error> {
iter.next()
.and_then(|token| token.into_text())
.ok_or(Error::missing_module_name())
}

fn skip_until_after_text_ignore_ascii_case(
iter: &mut IntoIter<Token>,
iter: &mut Peekable<IntoIter<Token>>,
text: &str,
) -> Result<(), Error> {
for t in iter {
Expand All @@ -275,7 +276,7 @@ impl Model<Asn> {
Err(Error::unexpected_end_of_stream())
}

fn read_imports(iter: &mut IntoIter<Token>) -> Result<Vec<Import>, Error> {
fn read_imports(iter: &mut Peekable<IntoIter<Token>>) -> Result<Vec<Import>, Error> {
let mut imports = Vec::new();
let mut import = Import::default();
while let Some(token) = iter.next() {
Expand All @@ -296,7 +297,10 @@ impl Model<Asn> {
}
Err(Error::unexpected_end_of_stream())
}
fn read_definition(iter: &mut IntoIter<Token>, name: String) -> Result<Definition<Asn>, Error> {
fn read_definition(
iter: &mut Peekable<IntoIter<Token>>,
name: String,
) -> Result<Definition<Asn>, Error> {
Self::next_separator_ignore_case(iter, ':')?;
Self::next_separator_ignore_case(iter, ':')?;
Self::next_separator_ignore_case(iter, '=')?;
Expand Down Expand Up @@ -328,7 +332,9 @@ impl Model<Asn> {
}
}

fn next_with_opt_tag(iter: &mut IntoIter<Token>) -> Result<(Token, Option<Tag>), Error> {
fn next_with_opt_tag(
iter: &mut Peekable<IntoIter<Token>>,
) -> Result<(Token, Option<Tag>), Error> {
let token = Self::next(iter)?;
if token.eq_separator('[') {
let tag = Tag::try_from(&mut *iter)?;
Expand All @@ -340,31 +346,39 @@ impl Model<Asn> {
}
}

fn read_role(iter: &mut IntoIter<Token>) -> Result<Type, Error> {
fn read_role(iter: &mut Peekable<IntoIter<Token>>) -> Result<Type, Error> {
let text = Self::next_text(iter)?;
Self::read_role_given_text(iter, text)
}

fn read_role_given_text(iter: &mut IntoIter<Token>, text: String) -> Result<Type, Error> {
fn read_role_given_text(
iter: &mut Peekable<IntoIter<Token>>,
text: String,
) -> Result<Type, Error> {
if text.eq_ignore_ascii_case("INTEGER") {
Self::next_separator_ignore_case(iter, '(')?;
let start = Self::next(iter)?;
Self::next_separator_ignore_case(iter, '.')?;
Self::next_separator_ignore_case(iter, '.')?;
let end = Self::next(iter)?;
Self::next_separator_ignore_case(iter, ')')?;
if start.eq_text("0") && end.eq_text_ignore_ascii_case("MAX") {
Ok(Type::Integer(None))
} else {
Ok(Type::Integer(Some(Range(
start
.text()
.and_then(|t| t.parse::<i64>().ok())
.ok_or_else(|| Error::invalid_range_value(start))?,
end.text()
.and_then(|t| t.parse::<i64>().ok())
.ok_or_else(|| Error::invalid_range_value(end))?,
))))
match iter.peek() {
Some(peeked) if peeked.eq_separator('(') => {
Self::next_separator_ignore_case(iter, '(')?;
let start = Self::next(iter)?;
Self::next_separator_ignore_case(iter, '.')?;
Self::next_separator_ignore_case(iter, '.')?;
let end = Self::next(iter)?;
Self::next_separator_ignore_case(iter, ')')?;
if start.eq_text("0") && end.eq_text_ignore_ascii_case("MAX") {
Ok(Type::Integer(None))
} else {
Ok(Type::Integer(Some(Range(
start
.text()
.and_then(|t| t.parse::<i64>().ok())
.ok_or_else(|| Error::invalid_range_value(start))?,
end.text()
.and_then(|t| t.parse::<i64>().ok())
.ok_or_else(|| Error::invalid_range_value(end))?,
))))
}
}
_ => Ok(Type::Integer(None)),
}
} else if text.eq_ignore_ascii_case("BOOLEAN") {
Ok(Type::Boolean)
Expand All @@ -388,7 +402,7 @@ impl Model<Asn> {
}
}

fn read_sequence_or_sequence_of(iter: &mut IntoIter<Token>) -> Result<Type, Error> {
fn read_sequence_or_sequence_of(iter: &mut Peekable<IntoIter<Token>>) -> Result<Type, Error> {
let token = Self::next(iter)?;

if token.eq_text_ignore_ascii_case("OF") {
Expand All @@ -410,7 +424,7 @@ impl Model<Asn> {
}
}

fn read_field(iter: &mut IntoIter<Token>) -> Result<(Field<Asn>, bool), Error> {
fn read_field(iter: &mut Peekable<IntoIter<Token>>) -> Result<(Field<Asn>, bool), Error> {
let name = Self::next_text(iter)?;
let (token, tag) = Self::next_with_opt_tag(iter)?;
let mut field = Field {
Expand All @@ -436,16 +450,16 @@ impl Model<Asn> {
}
}

fn next(iter: &mut IntoIter<Token>) -> Result<Token, Error> {
fn next(iter: &mut Peekable<IntoIter<Token>>) -> Result<Token, Error> {
iter.next().ok_or_else(Error::unexpected_end_of_stream)
}

fn next_text(iter: &mut IntoIter<Token>) -> Result<String, Error> {
fn next_text(iter: &mut Peekable<IntoIter<Token>>) -> Result<String, Error> {
Self::next(iter)?.into_text_or_else(Error::no_text)
}

fn next_separator_ignore_case(
iter: &mut IntoIter<Token>,
iter: &mut Peekable<IntoIter<Token>>,
separator: char,
) -> Result<(), Error> {
let token = Self::next(iter)?;
Expand Down Expand Up @@ -540,10 +554,10 @@ pub enum Tag {
ContextSpecific(usize),
}

impl TryFrom<&mut IntoIter<Token>> for Tag {
impl TryFrom<&mut Peekable<IntoIter<Token>>> for Tag {
type Error = Error;

fn try_from(iter: &mut IntoIter<Token>) -> Result<Self, Self::Error> {
fn try_from(iter: &mut Peekable<IntoIter<Token>>) -> Result<Self, Self::Error> {
macro_rules! parse_tag_number {
() => {
parse_tag_number!(Model::<Asn>::next(iter)?)
Expand Down Expand Up @@ -710,10 +724,10 @@ impl Choice {
}
}

impl TryFrom<&mut IntoIter<Token>> for Choice {
impl TryFrom<&mut Peekable<IntoIter<Token>>> for Choice {
type Error = Error;

fn try_from(iter: &mut IntoIter<Token>) -> Result<Self, Self::Error> {
fn try_from(iter: &mut Peekable<IntoIter<Token>>) -> Result<Self, Self::Error> {
Model::<Asn>::next_separator_ignore_case(iter, '{')?;
let mut choice = Choice {
variants: Vec::new(),
Expand Down Expand Up @@ -836,10 +850,10 @@ impl Enumerated {
}
}

impl TryFrom<&mut IntoIter<Token>> for Enumerated {
impl TryFrom<&mut Peekable<IntoIter<Token>>> for Enumerated {
type Error = Error;

fn try_from(iter: &mut IntoIter<Token>) -> Result<Self, Self::Error> {
fn try_from(iter: &mut Peekable<IntoIter<Token>>) -> Result<Self, Self::Error> {
Model::<Asn>::next_separator_ignore_case(iter, '{')?;
let mut enumerated = Self {
variants: Vec::new(),
Expand Down
9 changes: 9 additions & 0 deletions tests/basic_integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ asn_to_rust!(
RangedMax ::= Integer (0..MAX)
NotRanged ::= Integer
END"
);

#[test]
fn test_default_range() {
assert_eq!(RangedMax::value_min(), NotRanged::value_min());
assert_eq!(RangedMax::value_max(), NotRanged::value_max());
let _ = NotRanged(123_u64); // does not compile if the inner type is not u64
}

#[test]
fn test_uper() {
let mut buffer = BitBuffer::default();
Expand Down

0 comments on commit e367718

Please sign in to comment.