Yet another lifetime problem!

Hello everyone, it's my first topic here :slight_smile:
I got an annoying issue with lifetimes so here's the snippet (using the nom and json crates):

#[derive(PartialEq, Debug)]
enum MaskAtoms {
    Octave(u8),
    Length(u8),
    Volume(u8),
    Note(u8),
    Rest,
}

struct Mask(Vec<MaskAtoms>);

fn note<'a>(notes: &'a str) -> impl FnMut(&'a str) -> IResult<&'a str, MaskAtoms> {
    map_res(one_of(notes), move |c| {
        Ok::<MaskAtoms, Error>(MaskAtoms::Note(
            notes
                .find(c)
                .with_context(|| format!("unknown note: {}", c))?
                .try_into()
                .context("converting note index to u8 (shouldn't fail)")?,
        ))
    })
}

fn rest<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, MaskAtoms> {
    map_res(char('.'), move |_| Ok::<MaskAtoms, Error>(MaskAtoms::Rest))
}

fn length<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, MaskAtoms> {
    map_res(preceded(char('$'), map_res(digit1, str::parse)), move |n| {
        Ok::<MaskAtoms, Error>(MaskAtoms::Length(n))
    })
}

fn octave<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, MaskAtoms> {
    map_res(preceded(char('@'), map_res(digit1, str::parse)), move |n| {
        Ok::<MaskAtoms, Error>(MaskAtoms::Octave(n))
    })
}

fn volume<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, MaskAtoms> {
    map_res(preceded(char('!'), map_res(digit1, str::parse)), move |n| {
        Ok::<MaskAtoms, Error>(MaskAtoms::Volume(n))
    })
}

impl From<JsonValue> for Channel {
    fn from(value: JsonValue) -> Self {
        todo!()
    }
}

/// From the string mask and a string of allowed notes
impl TryFrom<JsonValue> for Mask {
    type Error = Error;
    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
        Ok(Mask(
            many0(preceded(
                space0,
                alt((
                    note(value["notes"].as_str()),
                    rest(),
                    length(),
                    octave(),
                    volume(),
                )),
            ))(value["mask"].as_str().unwrap())
            .context("cannot parse mask input")?
            .1,
        ))
    }
}

This TryFrom should parse the "mask" key using the "notes" key of a JsonValue object for this piece of JSON:

"piano": {
  "instrument": "piano-sample",
  "effects": [
    "low reverb"
  ],
  "notes": "aAbcCdDefFgG",
  "tuning": 442,
  "mask": "@4$4!100 a.cd"
},

It's my first time making TryFrom implementations and the compiler says this one is incorrect because the "borrowed value does not live long enough" (the "value" variable in argument). If I understand it correctly this value is only available at the first iteration but a clone doesn't seem to help.

Please give an example that actually produces the error you are talking about. You can use Rust Explorer to share code.

1 Like

I think your error cases are also borrowed. Try something like this:

+            .map_err(|e| e.to_owned())
             .context("cannot parse mask input")?
             .1,

Note the requirements for Result as Context.

3 Likes

I've created a playground with @quinedot's answer (had to replace json with serde_json though) and it compiles fine.

2 Likes

Thank you very much!
I can't believe this static comes from anyhow. I'll be more careful now!

The idea is that you can propagate the error up the call stack, out of main, to another thread, or whatever else.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.