Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ std = ["time"]
[dependencies]
byteorder = { version = "1", default-features = false }
clippy = { version = "^0", optional = true }
nom = { version = "7", default-features = false, features = ["alloc"] }
nom = { version = "8", default-features = false, features = ["alloc"] }
time = { version = "0.3.9", default-features = false, features = [
"formatting",
], optional = true }
Expand Down
46 changes: 27 additions & 19 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ impl Matcher {
pub fn new(pattern: &str) -> Result<Self, OscError> {
verify_address_pattern(pattern)?;
let mut match_fn = all_consuming(many1(map_address_pattern_component));
let (_, pattern_parts) =
match_fn(pattern).map_err(|err| OscError::BadAddressPattern(err.to_string()))?;
let (_, pattern_parts) = match_fn
.parse(pattern)
.map_err(|err| OscError::BadAddressPattern(err.to_string()))?;

Ok(Matcher {
pattern: pattern.into(),
Expand Down Expand Up @@ -142,7 +143,8 @@ fn pattern_choice(input: &str) -> IResult<&str, Vec<&str>> {
char('{'),
separated_list1(tag(","), take_while1(is_address_character)),
char('}'),
)(input)
)
.parse(input)
}

/// Parser to recognize a character class like [!a-zA-Z] and return '!a-zA-Z'
Expand All @@ -169,7 +171,7 @@ fn pattern_character_class(input: &str) -> IResult<&str, &str> {
))),
);

delimited(char('['), recognize(inner), char(']'))(input)
delimited(char('['), recognize(inner), char(']')).parse(input)
}

/// A characters class is defined by a set or range of characters that it matches.
Expand Down Expand Up @@ -204,7 +206,7 @@ impl CharacterClass {
pub fn new(s: &str) -> Self {
let mut input = s;
let negated;
match char::<_, nom::error::Error<&str>>('!')(input) {
match char::<_, nom::error::Error<&str>>('!').parse(input) {
Ok((i, _)) => {
negated = true;
input = i;
Expand All @@ -226,7 +228,8 @@ impl CharacterClass {
satisfy(is_address_character).map(|x| x.to_string()),
// Trailing dash
char('-').map(|_| String::from("-")),
))))(input);
))))
.parse(input);

match characters {
Ok((_, o)) => CharacterClass {
Expand Down Expand Up @@ -270,25 +273,26 @@ fn map_address_pattern_component(input: &str) -> IResult<&str, AddressPatternCom
}),
pattern_character_class
.map(|s: &str| AddressPatternComponent::CharacterClass(CharacterClass::new(s))),
))(input)
))
.parse(input)
}

fn match_literally<'a>(input: &'a str, pattern: &str) -> IResult<&'a str, &'a str> {
tag(pattern)(input)
tag(pattern).parse(input)
}

fn match_wildcard_single(input: &str) -> IResult<&str, &str> {
take_while_m_n(1, 1, is_address_character)(input)
take_while_m_n(1, 1, is_address_character).parse(input)
}

fn match_character_class<'a>(
input: &'a str,
character_class: &'a CharacterClass,
) -> IResult<&'a str, &'a str> {
if character_class.negated {
is_not(character_class.characters.as_str())(input)
is_not(character_class.characters.as_str()).parse(input)
} else {
is_a(character_class.characters.as_str())(input)
is_a(character_class.characters.as_str()).parse(input)
}
}

Expand All @@ -297,7 +301,7 @@ fn match_character_class<'a>(
/// It will get parsed into a vector containing the strings "foo" and "bar", which are then matched
fn match_choice<'a>(input: &'a str, choices: &[String]) -> IResult<&'a str, &'a str> {
for choice in choices {
if let Ok((i, o)) = tag::<_, _, nom::error::Error<&str>>(choice.as_str())(input) {
if let Ok((i, o)) = tag::<_, _, nom::error::Error<&str>>(choice.as_str()).parse(input) {
return Ok((i, o));
}
}
Expand All @@ -323,7 +327,8 @@ fn match_wildcard<'a>(
// No next component, consume all allowed characters until end or next '/'
None => verify(take_while1(is_address_character), |s: &str| {
s.len() >= minimum_length
})(input),
})
.parse(input),
// There is another element in this part, so logic gets a bit more complicated
Some(component) => {
// Wildcards can only match within the current address part, discard the rest
Expand Down Expand Up @@ -356,7 +361,7 @@ fn match_wildcard<'a>(
longest = i
}
}
verify(take(longest), |s: &str| s.len() >= minimum_length)(input)
verify(take(longest), |s: &str| s.len() >= minimum_length).parse(input)
}
}
}
Expand All @@ -373,10 +378,11 @@ fn match_wildcard<'a>(
/// }
/// ```
pub fn verify_address(input: &str) -> Result<(), OscError> {
match all_consuming::<_, _, nom::error::Error<&str>, _>(many1(pair(
match all_consuming::<_, nom::error::Error<&str>, _>(many1(pair(
tag("/"),
take_while1(is_address_character),
)))(input)
)))
.parse(input)
{
Ok(_) => Ok(()),
Err(_) => Err(OscError::BadAddress("Invalid address".to_string())),
Expand All @@ -385,13 +391,14 @@ pub fn verify_address(input: &str) -> Result<(), OscError> {

/// Parse an address pattern's part until the next '/' or the end
fn address_pattern_part_parser(input: &str) -> IResult<&str, Vec<&str>> {
many1::<_, _, nom::error::Error<&str>, _>(alt((
many1(alt((
take_while1(is_address_character),
tag("?"),
tag("*"),
recognize(pattern_choice),
pattern_character_class,
)))(input)
)))
.parse(input)
}

/// Verify that an address pattern is valid
Expand All @@ -409,7 +416,8 @@ pub fn verify_address_pattern(input: &str) -> Result<(), OscError> {
match all_consuming(many1(
// Each part must start with a '/'. This automatically also prevents a trailing '/'
pair(tag("/"), address_pattern_part_parser.map(|x| x.concat())),
))(input)
))
.parse(input)
{
Ok(_) => Ok(()),
Err(_) => Err(OscError::BadAddress("Invalid address pattern".to_string())),
Expand Down
41 changes: 25 additions & 16 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use nom::multi::many0;
use nom::number::complete::{be_f32, be_f64, be_i32, be_i64, be_u32};
use nom::sequence::terminated;
use nom::Offset;
use nom::{combinator::map_res, sequence::tuple, Err, IResult};
use nom::Parser;
use nom::{combinator::map_res, Err, IResult};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;
Expand Down Expand Up @@ -119,10 +120,11 @@ fn decode_bundle<'a>(
input: &'a [u8],
original_input: &'a [u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
let (input, (timetag, content)) = tuple((
let (input, (timetag, content)) = (
read_time_tag,
many0(|input| read_bundle_element(input, original_input)),
))(input)?;
)
.parse(input)?;

Ok((input, OscPacket::Bundle(OscBundle { timetag, content })))
}
Expand All @@ -142,7 +144,8 @@ fn read_bundle_element<'a>(
})
},
|input| decode_packet(input, original_input),
)(input)
)
.parse(input)
}

fn read_osc_string<'a>(
Expand All @@ -151,15 +154,16 @@ fn read_osc_string<'a>(
) -> IResult<&'a [u8], String, OscError> {
map_res(
terminated(
tuple((take_till(|c| c == 0u8), tag(b"\0"))),
(take_till(|c| c == 0u8), tag(&b"\0"[..])),
pad_to_32_bit_boundary(original_input),
),
|(str_buf, _null_byte)| {
String::from_utf8(str_buf.into())
.map_err(OscError::StringError)
.map(|s| s.trim_matches(0u8 as char).to_string())
},
)(input)
)
.parse(input)
}

fn read_osc_args<'a>(
Expand Down Expand Up @@ -205,10 +209,10 @@ fn read_osc_arg<'a>(
tag: char,
) -> IResult<&'a [u8], OscType, OscError> {
match tag {
'f' => map(be_f32, OscType::Float)(input),
'd' => map(be_f64, OscType::Double)(input),
'i' => map(be_i32, OscType::Int)(input),
'h' => map(be_i64, OscType::Long)(input),
'f' => map(be_f32, OscType::Float).parse(input),
'd' => map(be_f64, OscType::Double).parse(input),
'i' => map(be_i32, OscType::Int).parse(input),
'h' => map(be_i64, OscType::Long).parse(input),
's' => read_osc_string(input, original_input)
.map(|(remainder, string)| (remainder, OscType::String(string))),
't' => read_time_tag(input).map(|(remainder, time)| (remainder, OscType::Time(time))),
Expand All @@ -234,7 +238,8 @@ fn read_char(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
Some(c) => Ok(OscType::Char(c)),
None => Err(OscError::BadArg("Argument is not a char!".to_string())),
}
})(input)
})
.parse(input)
}

fn read_blob<'a>(
Expand All @@ -246,14 +251,16 @@ fn read_blob<'a>(
map(
terminated(take(size), pad_to_32_bit_boundary(original_input)),
|blob| OscType::Blob(blob.into()),
)(input)
)
.parse(input)
}

fn read_time_tag(input: &[u8]) -> IResult<&[u8], OscTime, OscError> {
map(tuple((be_u32, be_u32)), |(seconds, fractional)| OscTime {
map((be_u32, be_u32), |(seconds, fractional)| OscTime {
seconds,
fractional,
})(input)
})
.parse(input)
}

fn read_midi_message(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
Expand All @@ -264,7 +271,8 @@ fn read_midi_message(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
data1: buf[2],
data2: buf[3],
})
})(input)
})
.parse(input)
}

fn read_osc_color(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
Expand All @@ -275,7 +283,8 @@ fn read_osc_color(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
blue: buf[2],
alpha: buf[3],
})
})(input)
})
.parse(input)
}

fn pad_to_32_bit_boundary<'a>(
Expand Down