1

I want to use the midly crate for standard MIDI file (SMF) parsing. The parse function I want to call has this signature:

pub fn parse(raw: &[u8]) -> Result<Smf> 

When I try this

pub fn read0(path: &str) -> Smf {
    let data = fs::read(path).unwrap(); // a Vec<u8>
    Smf::parse(&data).unwrap()
}

I get the error

34 |     Smf::parse(&data).unwrap()
   |     ^^^^^^^^^^^-----^^^^^^^^^^
   |     |          |
   |     |          `data` is borrowed here
   |     returns a value referencing data owned by the current function

So the idea is to return both the data buffer and the parsed Smf together:

pub struct Ret2<'a> {
    data: Vec<u8>,
    smf: Smf<'a>,
}

pub fn read2(path: &str) -> Ret2 {
    let data = fs::read(path).unwrap();
    let smf = Smf::parse(&data).unwrap();
    Ret2 {data, smf}
}

But this does not work, since the compiler seems not to understand that both are returned together and complains about every item individually:

error[E0515]: cannot return value referencing local variable `data`
  --> src/bin/../midifile.rs:57:5
   |
56 |     let smf = Smf::parse(&data).unwrap();
   |                          ----- `data` is borrowed here
57 |     Ret2 {data, smf}
   |     ^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `data` because it is borrowed
  --> src/bin/../midifile.rs:57:11
   |
54 | pub fn read2(path: &str) -> Ret2 {
   |                    - let's call the lifetime of this reference `'1`
55 |     let data = fs::read(path).unwrap();
56 |     let smf = Smf::parse(&data).unwrap();
   |                          ----- borrow of `data` occurs here
57 |     Ret2 {data, smf}
   |     ------^^^^------
   |     |     |
   |     |     move out of `data` occurs here
   |     returning this value requires that `data` is borrowed for `'1`

How must this be done in Rust?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I am curious how the general problem is solved, yet I think that your concrete problem could be solved simpler by just returning an owned data type from `Smf::parse`. – CoronA Dec 15 '19 at 16:54
  • If you look at the [source](https://docs.rs/midly/0.3.0/src/midly/smf.rs.html#23-25) of midly you can see that `parse` calls `read` which has this signature: `pub fn read(raw: &'a [u8]) -> Result>`. I might be wrong, but the lifetime of the reference might confuse the compiler. Because the resulting Smf struct does not reference `raw` as far as I can see from the code. – joarfish Dec 15 '19 at 17:40
  • @kastenbutt If you're right, then this is the bug in midly. But I'm not so sure that there is really no reference (with only a brief look on the source code). – Cerberus Dec 15 '19 at 17:52
  • I had another look at the code of midly. `Smf` uses `Event`, which uses `EventKind` which in turn keeps a reference to the raw-data. So, this is not a bug but unexpected for a user of midly nevertheless. To work around this you need to keep ownership of `data` yourself as long as the Smf instance you created from the `data` is alive. – joarfish Dec 15 '19 at 22:15
  • Thank you for the link with the detailed answer. So maybe the ownig_ref crate could help. But how to tell a non-rusticean the reason for all that additional code? midly has those references to the raw data though you might not be interested at all in them. Perhaps I'll give nom_midi a try, though the documentation is very short. – Harald Rieder Dec 16 '19 at 13:57
  • Thanks to all, I learned much now. – Harald Rieder Dec 16 '19 at 14:02

0 Answers0