dbschwartz
dbschwartz

Reputation: 783

Is there a recommended pattern for building Flatbuffers that have nested types?

I have a flatbuffers schema with many nested tables. In the Typescript flatbuffers I was able to have each table expose a to_offset function that returned the WIPOffset for the table on creation time. Then I could assign the result to the nested field in a higher level type, and it worked very well.

In the Rust flatbuffers I cannot make this work as it requires more than one mutable borrow, which of course is not allowed.

Is there any way you recommend working with nested schemas like this where various tables are used throughout the schema in higher level types?

Here is a rough example of what I would like to do:


table A {
  f1: string;
}
    
table B {
  fa: A;
  f2: uint;
}

table C {
  fa: A;
  f3: ushort;
}

fn build_a_offset<'a>(fbb: &'a mut FlatBufferBuilder) -> WIPOffset<A<'a>> {
  let args = AArgs {...
  };

  let a = A::create(fbb, &args);

  a
}

fn build_b_buf() -> Vec<u8> {
  let mut fbb = FlatBufferBuilder::new_with_capacity(1024);
  
  let a_offset = build_a_offset(&mut fbb);

  let b_args = BArgs {
    a: a_offset,
    f2: 30u32,
  }

  let b = B::create(&mut fbb, f_args);

  fbb.finish(b); 

  fbb.finished_data().to_vec()

}

Any suggestions on how to structure this properly will be very helpful.

Upvotes: 0

Views: 1107

Answers (1)

dbschwartz
dbschwartz

Reputation: 783

I did find an answer, I was not using lifetimes correctly.

fn build_a_offset<'a>(fbb: &'mut FlatBufferBuilder<'fbb>) -> WIPOffset<A<'a>> {
  let args = AArgs {...
  };

  let a = A::create(fbb, &args);

  a
}

fn build_b_buf() -> Vec<u8> {
  let mut fbb = FlatBufferBuilder::new_with_capacity(1024);
  
  let a_offset = build_a_offset(&mut fbb);

  let b_args = BArgs {
    a: a_offset,
    f2: 30u32,
  }

  let b = B::create(&mut fbb, f_args);

  fbb.finish(b); 

  fbb.finished_data().to_vec()

}

I needed to change the signature for the fbb ref to this:

fbb: &'mut FlatBufferBuilder<'fbb>

It was appending the suffix lifetime instead of the lifetime prepending the reference. This is because a prepended lifetime controls the life of the reference, and what is required is to control the life of the data included in the reference (that is what an appended <'fbb> does in Rust).

It would be good to add more examples to the tutorial for things like this. I could help at some point if that is something you need.

Upvotes: 2

Related Questions