Can I iterate over all the table items with FlatBuffers? - rust

I have the following FlatBuffers schema (simplified):
table StringNode {
prefix: StringNode;
suffix: StringNode;
value: string (required);
}
table NodesData {
url1: StringNode (required);
url2: StringNode (required);
url3: StringNode (required);
}
root_type NodesData;
Is there a way to iterate all StringNodes without having separate urls: [StringNode] and adding them while encoding?
I don't see anything similar in generated Rust code.
PS. The Rust code can be generated using flatc --rust filename. here is what i have:
// automatically generated by the FlatBuffers compiler, do not modify
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod com {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod company {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod project {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod fb {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod node {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
pub enum StringNodeOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct StringNode<'a> {
pub _tab: flatbuffers::Table<'a>,
}
impl<'a> flatbuffers::Follow<'a> for StringNode<'a> {
type Inner = StringNode<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table { buf, loc } }
}
}
impl<'a> StringNode<'a> {
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
StringNode { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args StringNodeArgs<'args>) -> flatbuffers::WIPOffset<StringNode<'bldr>> {
let mut builder = StringNodeBuilder::new(_fbb);
if let Some(x) = args.value { builder.add_value(x); }
if let Some(x) = args.suffix { builder.add_suffix(x); }
if let Some(x) = args.prefix { builder.add_prefix(x); }
builder.finish()
}
pub const VT_PREFIX: flatbuffers::VOffsetT = 4;
pub const VT_SUFFIX: flatbuffers::VOffsetT = 6;
pub const VT_VALUE: flatbuffers::VOffsetT = 8;
#[inline]
pub fn prefix(&self) -> Option<StringNode<'a>> {
self._tab.get::<flatbuffers::ForwardsUOffset<StringNode>>(StringNode::VT_PREFIX, None)
}
#[inline]
pub fn suffix(&self) -> Option<StringNode<'a>> {
self._tab.get::<flatbuffers::ForwardsUOffset<StringNode>>(StringNode::VT_SUFFIX, None)
}
#[inline]
pub fn value(&self) -> &'a str {
self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(StringNode::VT_VALUE, None).unwrap()
}
}
impl flatbuffers::Verifiable for StringNode<'_> {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<flatbuffers::ForwardsUOffset<StringNode>>(&"prefix", Self::VT_PREFIX, false)?
.visit_field::<flatbuffers::ForwardsUOffset<StringNode>>(&"suffix", Self::VT_SUFFIX, false)?
.visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"value", Self::VT_VALUE, true)?
.finish();
Ok(())
}
}
pub struct StringNodeArgs<'a> {
pub prefix: Option<flatbuffers::WIPOffset<StringNode<'a>>>,
pub suffix: Option<flatbuffers::WIPOffset<StringNode<'a>>>,
pub value: Option<flatbuffers::WIPOffset<&'a str>>,
}
impl<'a> Default for StringNodeArgs<'a> {
#[inline]
fn default() -> Self {
StringNodeArgs {
prefix: None,
suffix: None,
value: None, // required field
}
}
}
pub struct StringNodeBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> StringNodeBuilder<'a, 'b> {
#[inline]
pub fn add_prefix(&mut self, prefix: flatbuffers::WIPOffset<StringNode<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<StringNode>>(StringNode::VT_PREFIX, prefix);
}
#[inline]
pub fn add_suffix(&mut self, suffix: flatbuffers::WIPOffset<StringNode<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<StringNode>>(StringNode::VT_SUFFIX, suffix);
}
#[inline]
pub fn add_value(&mut self, value: flatbuffers::WIPOffset<&'b str>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(StringNode::VT_VALUE, value);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> StringNodeBuilder<'a, 'b> {
let start = _fbb.start_table();
StringNodeBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<StringNode<'a>> {
let o = self.fbb_.end_table(self.start_);
self.fbb_.required(o, StringNode::VT_VALUE,"value");
flatbuffers::WIPOffset::new(o.value())
}
}
impl std::fmt::Debug for StringNode<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ds = f.debug_struct("StringNode");
ds.field("prefix", &self.prefix());
ds.field("suffix", &self.suffix());
ds.field("value", &self.value());
ds.finish()
}
}
pub enum NodesDataOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct NodesData<'a> {
pub _tab: flatbuffers::Table<'a>,
}
impl<'a> flatbuffers::Follow<'a> for NodesData<'a> {
type Inner = NodesData<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table { buf, loc } }
}
}
impl<'a> NodesData<'a> {
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
NodesData { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args NodesDataArgs<'args>) -> flatbuffers::WIPOffset<NodesData<'bldr>> {
let mut builder = NodesDataBuilder::new(_fbb);
if let Some(x) = args.url3 { builder.add_url3(x); }
if let Some(x) = args.url2 { builder.add_url2(x); }
if let Some(x) = args.url1 { builder.add_url1(x); }
builder.finish()
}
pub const VT_URL1: flatbuffers::VOffsetT = 4;
pub const VT_URL2: flatbuffers::VOffsetT = 6;
pub const VT_URL3: flatbuffers::VOffsetT = 8;
#[inline]
pub fn url1(&self) -> StringNode<'a> {
self._tab.get::<flatbuffers::ForwardsUOffset<StringNode>>(NodesData::VT_URL1, None).unwrap()
}
#[inline]
pub fn url2(&self) -> StringNode<'a> {
self._tab.get::<flatbuffers::ForwardsUOffset<StringNode>>(NodesData::VT_URL2, None).unwrap()
}
#[inline]
pub fn url3(&self) -> StringNode<'a> {
self._tab.get::<flatbuffers::ForwardsUOffset<StringNode>>(NodesData::VT_URL3, None).unwrap()
}
}
impl flatbuffers::Verifiable for NodesData<'_> {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<flatbuffers::ForwardsUOffset<StringNode>>(&"url1", Self::VT_URL1, true)?
.visit_field::<flatbuffers::ForwardsUOffset<StringNode>>(&"url2", Self::VT_URL2, true)?
.visit_field::<flatbuffers::ForwardsUOffset<StringNode>>(&"url3", Self::VT_URL3, true)?
.finish();
Ok(())
}
}
pub struct NodesDataArgs<'a> {
pub url1: Option<flatbuffers::WIPOffset<StringNode<'a>>>,
pub url2: Option<flatbuffers::WIPOffset<StringNode<'a>>>,
pub url3: Option<flatbuffers::WIPOffset<StringNode<'a>>>,
}
impl<'a> Default for NodesDataArgs<'a> {
#[inline]
fn default() -> Self {
NodesDataArgs {
url1: None, // required field
url2: None, // required field
url3: None, // required field
}
}
}
pub struct NodesDataBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> NodesDataBuilder<'a, 'b> {
#[inline]
pub fn add_url1(&mut self, url1: flatbuffers::WIPOffset<StringNode<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<StringNode>>(NodesData::VT_URL1, url1);
}
#[inline]
pub fn add_url2(&mut self, url2: flatbuffers::WIPOffset<StringNode<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<StringNode>>(NodesData::VT_URL2, url2);
}
#[inline]
pub fn add_url3(&mut self, url3: flatbuffers::WIPOffset<StringNode<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<StringNode>>(NodesData::VT_URL3, url3);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> NodesDataBuilder<'a, 'b> {
let start = _fbb.start_table();
NodesDataBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<NodesData<'a>> {
let o = self.fbb_.end_table(self.start_);
self.fbb_.required(o, NodesData::VT_URL1,"url1");
self.fbb_.required(o, NodesData::VT_URL2,"url2");
self.fbb_.required(o, NodesData::VT_URL3,"url3");
flatbuffers::WIPOffset::new(o.value())
}
}
impl std::fmt::Debug for NodesData<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ds = f.debug_struct("NodesData");
ds.field("url1", &self.url1());
ds.field("url2", &self.url2());
ds.field("url3", &self.url3());
ds.finish()
}
}
#[inline]
#[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_nodes_data<'a>(buf: &'a [u8]) -> NodesData<'a> {
unsafe { flatbuffers::root_unchecked::<NodesData<'a>>(buf) }
}
#[inline]
#[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_nodes_data<'a>(buf: &'a [u8]) -> NodesData<'a> {
unsafe { flatbuffers::size_prefixed_root_unchecked::<NodesData<'a>>(buf) }
}
#[inline]
/// Verifies that a buffer of bytes contains a `NodesData`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_nodes_data_unchecked`.
pub fn root_as_nodes_data(buf: &[u8]) -> Result<NodesData, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root::<NodesData>(buf)
}
#[inline]
/// Verifies that a buffer of bytes contains a size prefixed
/// `NodesData` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_nodes_data_unchecked`.
pub fn size_prefixed_root_as_nodes_data(buf: &[u8]) -> Result<NodesData, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root::<NodesData>(buf)
}
#[inline]
/// Verifies, with the given options, that a buffer of bytes
/// contains a `NodesData` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_nodes_data_unchecked`.
pub fn root_as_nodes_data_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<NodesData<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root_with_opts::<NodesData<'b>>(opts, buf)
}
#[inline]
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `NodesData` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_nodes_data_unchecked`.
pub fn size_prefixed_root_as_nodes_data_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<NodesData<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root_with_opts::<NodesData<'b>>(opts, buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a NodesData and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `NodesData`.
pub unsafe fn root_as_nodes_data_unchecked(buf: &[u8]) -> NodesData {
flatbuffers::root_unchecked::<NodesData>(buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed NodesData and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `NodesData`.
pub unsafe fn size_prefixed_root_as_nodes_data_unchecked(buf: &[u8]) -> NodesData {
flatbuffers::size_prefixed_root_unchecked::<NodesData>(buf)
}
#[inline]
pub fn finish_nodes_data_buffer<'a, 'b>(
fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
root: flatbuffers::WIPOffset<NodesData<'a>>) {
fbb.finish(root, None);
}
#[inline]
pub fn finish_size_prefixed_nodes_data_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<NodesData<'a>>) {
fbb.finish_size_prefixed(root, None);
}
} // pub mod node
} // pub mod fb
} // pub mod project
} // pub mod company
} // pub mod com
But the questions is "even if the getter code is not generated by flatc Rust plugin, is it doable in general?". If following db concept that should be doable.
PPS. flatc "2.0.0" is used, flatbuffers "2.0.0" crate is used.

No, you can't. FlatBuffer fields are not necessarily contiguous in memory, and they potentially all have different types, so there is no way to iterate them.
While that potentially could be implemented with sufficient trickery (visitors?) there isn't a lot of point, especially in a system that is efficiency oriented.
Like you already say so yourself, you really want to be using a [StringNode] in cases like this.

Related

Rust - Casting super trait to trait

I have a container where I can store items implementing the CommonBase trait and I have some other traits (TypeA and TypeB for example, but there can be unknown number of other TypeX traits) with the CommonBase as their super trait. I store objects implementing ItemA to container and I can get a reference to item back from the container, but as reference to the CommonBase.
I want to cast the item back to its original type like this:
fn cast_to<T: SuperTrait>(val: dyn CommonBase) -> Result<T, dyn Error> {...}
Can anyone help please?
Here is my experimental code
use std::error::Error;
use std::rc::Rc;
pub trait CommonBase {
fn to_common(self: &Self);
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) { todo!() }
}
impl TypeA for StructA {
fn do_a(self: &Self) { todo!() }
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) { todo!() }
}
impl TypeB for StructB {
fn do_b(self: &Self) { todo!() }
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(self: &mut Self, item: Rc<dyn CommonBase>) {
self.items.push(item);
}
pub fn get(self, idx: usize) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(val: Rc<dyn CommonBase>) -> Result<Rc<dyn T>, Box<dyn Error>> {...} // <- some magic is done here
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get_common(0); // actually TypeA
let stored_a: Rc<dyn TypeA> = cast_to(stored_a_as_common).unwrap();
stored_a.do_a();
}
Here is your code with a few additions.
For this, you need std::any::Any.
Each struct subject to dynamic cast should be known as dyn Any in order to try the dynamic cast; this is the purpose of .as_any() and .as_any_mut() in the example.
Using .downcast_ref() or .downcast_mut() requires you target a type, not a trait.
I don't think you can have at the same time two Rcs pointing towards the same struct but declared with different dyn traits.
The best to do, in my opinion, is to only deal with references (wherever they come from, Rc or something else).
You expected an Error when the dynamic cast is impossible, then I wrote the function this way.
Note however that .downcast_ref() returns an Option and this is generally good enough (None means that the cast is impossible); we could simplify the code with just this line val.as_any().downcast_ref::<T>().
use std::error::Error;
use std::rc::Rc;
use std::any::Any;
pub trait CommonBase: Any {
fn to_common(self: &Self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeA for StructA {
fn do_a(self: &Self) {
println!("doing a");
}
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeB for StructB {
fn do_b(self: &Self) {
println!("doing b");
}
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(
self: &mut Self,
item: Rc<dyn CommonBase>,
) {
self.items.push(item);
}
pub fn get(
&self,
idx: usize,
) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(
val: &dyn CommonBase
) -> Result<&T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any().downcast_ref::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
#[allow(dead_code)] // unused in this example
fn cast_to_mut<T: CommonBase>(
val: &mut dyn CommonBase
) -> Result<&mut T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any_mut().downcast_mut::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get(0); // actually TypeA
let stored_a: &dyn TypeA =
cast_to::<StructA>(stored_a_as_common.as_ref()).unwrap();
stored_a.do_a();
let stored_b_as_common: Rc<dyn CommonBase> = container.get(1); // actually TypeB
let stored_b: &dyn TypeB =
cast_to::<StructB>(stored_b_as_common.as_ref()).unwrap();
stored_b.do_b();
}
/*
doing a
doing b
*/

Rust mutably borrowed lifetime issue

This is en excerpt from my actual code, but the issue is the same. I cannot borrow the staging_buffer in Buffer::from_data as mutable, and I cannot figure out why this is the case. Why isn't the mutable borrow of the Memory<'a> from the staging_Buffer released when the block is finished?
Note that the u32 reference in the Device struct is just a dummy, and in practice is a non-copyable type.
pub struct Device<'a> {
id: &'a u32,
}
impl<'a> Device<'a> {
pub fn new(id: &'a u32) -> Self {
Self { id }
}
}
pub struct Memory<'a> {
device: &'a Device<'a>,
}
impl<'a> Memory<'a> {
pub fn new(device: &'a Device) -> Self {
Self { device }
}
pub fn map(&mut self) {}
pub fn unmap(&mut self) {}
pub fn copy_from_host<T>(&self, _slice: &[T]) {}
}
impl<'a> Drop for Memory<'a> {
fn drop(&mut self) {}
}
pub struct Buffer<'a> {
device: &'a Device<'a>,
memory: Memory<'a>,
}
impl<'a> Buffer<'a> {
pub fn new(device: &'a Device) -> Self {
let buffer_memory = Memory::new(device);
Self {
device,
memory: buffer_memory,
}
}
pub fn from_data<T: Copy>(device: &'a Device, _data: &[T]) -> Self {
let mut staging_buffer = Buffer::new(device);
{
let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer_memory.map();
staging_buffer_memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
pub fn memory(&self) -> &Memory {
&self.memory
}
pub fn memory_mut(&'a mut self) -> &mut Memory {
&mut self.memory
}
fn copy_to_buffer(&self, _dst_buffer: &Buffer) {
//
}
}
impl<'a> Drop for Buffer<'a> {
fn drop(&mut self) {}
}
fn main() {
let id = 5;
let device = Device::new(&id);
let _buffer = Buffer::new(&device);
}
Okay, I finally figured it out!
The error here is actually in your implementation of memory_mut, and not in the rest of the code (although I agree that the lifetimes and references are making things harder than they need to be).
One way to see that this is the issue is to just mutably borrow memory directly, like so.
...
pub fn from_data<T: Copy>(device: &'a Device, _data: &[T]) -> Self {
let mut staging_buffer = Buffer::new(device);
{
// Don't use the stagin_buffer_memory variable
// let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer.memory.map();
staging_buffer.memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
...
but instead you can fix memory_mut by rewriting it like this:
...
pub fn memory_mut(&mut self) -> &mut Memory<'a> {
&mut self.memory
}
...
In this case the implementation of from_data works as it should.
I am not very confident with this, but I think it is due to the fact that the same lifetime annotation 'a is used everywhere.
Then, when lifetimes are considered by the borrow-checker, some are supposed to be equivalent (because of the same annotation) although they are not.
A lifetime is indeed necessary for the reference id in Device.
Another is needed for the reference device in Memory but this is not necessarily the same as the previous.
Then, I propagated these distinct lifetimes all over the code.
A Rust expert could probably explain this better than me.
pub struct Device<'i> {
id: &'i u32,
}
impl<'i> Device<'i> {
pub fn new(id: &'i u32) -> Self {
Self { id }
}
}
pub struct Memory<'d, 'i> {
device: &'d Device<'i>,
}
impl<'d, 'i> Memory<'d, 'i> {
pub fn new(device: &'d Device<'i>) -> Self {
Self { device }
}
pub fn map(&mut self) {}
pub fn unmap(&mut self) {}
pub fn copy_from_host<T>(
&self,
_slice: &[T],
) {
}
}
impl<'d, 'i> Drop for Memory<'d, 'i> {
fn drop(&mut self) {}
}
pub struct Buffer<'d, 'i> {
device: &'d Device<'i>,
memory: Memory<'d, 'i>,
}
impl<'d, 'i> Buffer<'d, 'i> {
pub fn new(device: &'d Device<'i>) -> Self {
let buffer_memory = Memory::new(device);
Self {
device,
memory: buffer_memory,
}
}
pub fn from_data<T: Copy>(
device: &'d Device<'i>,
_data: &[T],
) -> Self {
let mut staging_buffer = Buffer::new(device);
{
let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer_memory.map();
staging_buffer_memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
pub fn memory(&self) -> &Memory<'d, 'i> {
&self.memory
}
pub fn memory_mut(&mut self) -> &mut Memory<'d, 'i> {
&mut self.memory
}
fn copy_to_buffer(
&self,
_dst_buffer: &Buffer,
) {
//
}
}
impl<'d, 'i> Drop for Buffer<'d, 'i> {
fn drop(&mut self) {}
}
fn main() {
let id = 5;
let device = Device::new(&id);
let _buffer = Buffer::new(&device);
}

Optional trait's method: call empty method or skip it at all?

If I have an optional method that has to be called many many times what is better if I want to skip it: have an empty body and call it or check the bool/Option before calling it?
The following benchmark make no sense. It gave zeroes.
#![feature(test)]
extern crate test;
trait OptTrait: 'static {
fn cheap_call(&mut self, data: u8);
fn expensive_call(&mut self, data: u8);
}
type ExpensiveFnOf<T> = &'static dyn Fn(&mut T, u8);
struct Container<T: OptTrait> {
inner: T,
expensive_fn: Option<ExpensiveFnOf<T>>,
}
impl<T: OptTrait> Container<T> {
fn new(inner: T, expensive: bool) -> Self {
let expensive_fn = {
if expensive {
Some(&T::expensive_call as ExpensiveFnOf<T>)
} else {
None
}
};
Self {
inner,
expensive_fn,
}
}
}
struct MyStruct;
impl OptTrait for MyStruct {
fn cheap_call(&mut self, _data: u8) {
}
fn expensive_call(&mut self, _data: u8) {
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[bench]
fn bench_always_call_empty(b: &mut Bencher) {
let mut cont = Container::new(MyStruct, false);
b.iter(|| {
cont.inner.cheap_call(0);
cont.inner.expensive_call(1);
});
}
#[bench]
fn bench_alwaws_skip_empty(b: &mut Bencher) {
let mut cont = Container::new(MyStruct, false);
b.iter(|| {
cont.inner.cheap_call(0);
if let Some(func) = cont.expensive_fn {
func(&mut cont.inner, 1);
}
});
}
}

Returning a mutable reference to a value behind Arc and Mutex

pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> &mut Vec<TreeLine> {
???????????????????????????????
}
}
I need help writing the get_the_forest function. I've tried many various things but they all return compilation errors. I need to return a mutable reference to Vec<TreeLine> which is wrapped behind an Arc and a Mutex in self.m_tree_lines.
There is no way of doing this.
You create a concrete MutexGuard object that releases the mutex when it dropped when you call lock; you cannot move a reference out of the scope that contains the guard:
pub fn as_mut(&mut self) -> &Whatever {
let mut guard = self.data.lock().unwrap();
Ok(guard.deref())
drop(guard) // <--- implicitly added here, which would invalidate the ref
}
You also cannot return both the mutex guard and a reference, for more complex reasons (basically rust cannot express that), for the same reason it cannot have a reference and an object in a single structure; see the discussion on Why can't I store a value and a reference to that value in the same struct?
...so basically your best bet is one of two things:
/// Return the mutex guard itself
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
/// Pass a function in, which patches the mutable internal value
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard); // <-- patch happens while guard is still alive
Ok(())
}
Full code:
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::PoisonError;
use std::error::Error;
use std::fmt;
use std::fmt::Formatter;
use std::ops::Deref;
#[derive(Debug, Copy, Clone)]
pub enum TreeLockError {
FailedToLock
}
impl Error for TreeLockError {}
impl fmt::Display for TreeLockError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl<T> From<PoisonError<T>> for TreeLockError {
fn from(_: PoisonError<T>) -> Self {
TreeLockError::FailedToLock
}
}
// ---
#[derive(Debug)]
pub struct TreeLine {
pub value: &'static str
}
pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard);
Ok(())
}
}
fn main() -> Result<(), Box<dyn Error>> {
let mut vm = ForesterViewModel::new();
{
let mut trees = vm.get_the_forest()?;
trees.push(TreeLine{ value: "one"});
trees.push(TreeLine{ value: "two"});
} // <--- Drop the mutable reference here so you can get it again later
// Patch
vm.patch_forest(|trees| {
trees.push(TreeLine{ value: "three"});
});
// ...
let trees = vm.get_the_forest()?;
println!("{:?}", trees.deref());
Ok(())
}

Is there an owned version of String::chars?

The following code does not compile:
use std::str::Chars;
struct Chunks {
remaining: Chars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars(),
}
}
}
The error is:
error[E0106]: missing lifetime specifier
--> src/main.rs:4:16
|
4 | remaining: Chars,
| ^^^^^ expected lifetime parameter
Chars doesn't own the characters it iterates over and it can't outlive the &str or String it was created from.
Is there an owned version of Chars that does not need a lifetime parameter or do I have to keep a Vec<char> and an index myself?
std::vec::IntoIter is an owned version of every iterator, in a sense.
use std::vec::IntoIter;
struct Chunks {
remaining: IntoIter<char>,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars().collect::<Vec<_>>().into_iter(),
}
}
}
Playground link
Downside is additional allocation and a space overhead, but I am not aware of the iterator for your specific case.
Ouroboros
You can use the ouroboros crate to create a self-referential struct containing the String and a Chars iterator:
use ouroboros::self_referencing; // 0.4.1
use std::str::Chars;
#[self_referencing]
pub struct IntoChars {
string: String,
#[borrows(string)]
chars: Chars<'this>,
}
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.with_mut(|me| me.chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.with(|me| me.chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoCharsBuilder {
string: self,
chars_builder: |s| s.chars(),
}
.build()
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
Rental
You can use the rental crate to create a self-referential struct containing the String and a Chars iterator:
#[macro_use]
extern crate rental;
rental! {
mod into_chars {
pub use std::str::Chars;
#[rental]
pub struct IntoChars {
string: String,
chars: Chars<'string>,
}
}
}
use into_chars::IntoChars;
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.rent_mut(|chars| chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.rent(|chars| chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoChars::new(self, |s| s.chars())
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
There's also the owned-chars crate, which
provides an extension trait for String with two methods, into_chars and into_char_indices. These methods parallel String::chars and String::char_indices, but the iterators they create consume the String instead of borrowing it.
You could implement your own iterator, or wrap Chars like this (with just one small unsafe block):
// deriving Clone would be buggy. With Rc<>/Arc<> instead of Box<> it would work though.
struct OwnedChars {
// struct fields are dropped in order they are declared,
// see https://stackoverflow.com/a/41056727/1478356
// with `Chars` it probably doesn't matter, but for good style `inner`
// should be dropped before `storage`.
// 'static lifetime must not "escape" lifetime of the struct
inner: ::std::str::Chars<'static>,
// we need to box anyway to be sure the inner reference doesn't move when
// moving the storage, so we can erase the type as well.
// struct OwnedChar<S: AsRef<str>> { ..., storage: Box<S> } should work too
storage: Box<AsRef<str>>,
}
impl OwnedChars {
pub fn new<S: AsRef<str>+'static>(s: S) -> Self {
let storage = Box::new(s) as Box<AsRef<str>>;
let raw_ptr : *const str = storage.as_ref().as_ref();
let ptr : &'static str = unsafe { &*raw_ptr };
OwnedChars{
storage: storage,
inner: ptr.chars(),
}
}
pub fn as_str(&self) -> &str {
self.inner.as_str()
}
}
impl Iterator for OwnedChars {
// just `char` of course
type Item = <::std::str::Chars<'static> as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl DoubleEndedIterator for OwnedChars {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
impl Clone for OwnedChars {
fn clone(&self) -> Self {
// need a new allocation anyway, so simply go for String, and just
// clone the remaining string
OwnedChars::new(String::from(self.inner.as_str()))
}
}
impl ::std::fmt::Debug for OwnedChars {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let storage : &str = self.storage.as_ref().as_ref();
f.debug_struct("OwnedChars")
.field("storage", &storage)
.field("inner", &self.inner)
.finish()
}
}
// easy access
trait StringExt {
fn owned_chars(self) -> OwnedChars;
}
impl<S: AsRef<str>+'static> StringExt for S {
fn owned_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
See playground
As copied from How can I store a Chars iterator in the same struct as the String it is iterating on?:
use std::mem;
use std::str::Chars;
/// I believe this struct to be safe because the String is
/// heap-allocated (stable address) and will never be modified
/// (stable address). `chars` will not outlive the struct, so
/// lying about the lifetime should be fine.
///
/// TODO: What about during destruction?
/// `Chars` shouldn't have a destructor...
struct OwningChars {
_s: String,
chars: Chars<'static>,
}
impl OwningChars {
fn new(s: String) -> Self {
let chars = unsafe { mem::transmute(s.chars()) };
OwningChars { _s: s, chars }
}
}
impl Iterator for OwningChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next()
}
}
Here is a solution without unsafe.
It provides the same effect as s.chars().collect::<Vec<_>>().into_iter(), but without the allocation overhead.
struct OwnedChars {
s: String,
index: usize,
}
impl OwnedChars {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
Together with a little bit of trait magic:
trait StringExt {
fn into_chars(self) -> OwnedChars;
}
impl StringExt for String {
fn into_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
You can do:
struct Chunks {
remaining: OwnedChars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.into_chars(),
}
}
}

Resources