3

I have binary data packet with a UUID (16 bytes), a 1 byte type field and 4 bytes containing a float value.

How to parse with nom and get as result a tuple (Uuid, u8, f32)?

use nom::{
    combinator::map_res, number::complete::le_f32, number::complete::le_u128,
    number::complete::le_u8, sequence::tuple, IResult,
};
use uuid;

fn detect(data: &[u8]) -> IResult<&[u8], (uuid::Uuid, u8, f32)> {
    ???

    /* my attempt so far: 
    map_res(tuple((le_u128, le_u8, le_f32)), |tup| {
        Ok((uuid::Uuid::from_u128(tup.0), tup.1, tup.2))
    })(data)
    */
}

fn main() {
    let pdu = [
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 200, 65,
    ];

    let result = detect(&pdu);
    println!("{:?}", result);
}
[dependencies]
nom = "5"
uuid = "0.8"
Stargateur
  • 24,473
  • 8
  • 65
  • 91
attdona
  • 17,196
  • 7
  • 49
  • 60

2 Answers2

3

In nom 5, you can just use classic rust way, example is self describing:

use nom::combinator;
use nom::number::complete as number;

fn detect(data: &[u8]) -> nom::IResult<&[u8], (uuid::Uuid, u8, f32)> {
    let (data, uuid) = combinator::map(number::le_u128, uuid::Uuid::from_u128)(data)?;
    let (data, type_field) = number::le_u8(data)?;
    let (data, value) = number::le_f32(data)?;

    Ok((data, (uuid, type_field, value)))
}

fn main() {
    let pdu = [
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 200, 65,
    ];

    let result = detect(&pdu);
    println!("{:?}", result);
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • Many Thanks! I attempted to use `map_res`: it is wrong because it wrap the returning result into a Result. As shown in your answer, `map` it is the right combinator to use. – attdona Mar 13 '20 at 11:06
1

I've just fixed your attempt. You can implement, ore use, a more useful error.

use nom::{
    combinator::map_res, number::complete::le_f32, number::complete::le_u128,
    number::complete::le_u8, sequence::tuple, IResult,
};
use std::fmt::{Display, Formatter};
use uuid;

#[derive(Debug)]
struct Error;

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "Error")
    }
}

impl std::error::Error for Error {}

fn detect(data: &[u8]) -> IResult<&[u8], (uuid::Uuid, u8, f32)> {
    map_res(
        tuple((le_u128, le_u8, le_f32)),
        |tup: (u128, u8, f32)| -> Result<(uuid::Uuid, u8, f32), Error> {
            Ok((uuid::Uuid::from_u128(tup.0), tup.1, tup.2))
        },
    )(data)
}

fn main() {
    let pdu = [
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 200, 65,
    ];

    let result = detect(&pdu);
    println!("{:?}", result);
}
iclac
  • 96
  • 1
  • 3