Rust mutably borrowed lifetime issue - rust

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);
}

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
*/

How to use the typestate pattern in other struct

I want to use the typestate pattern to define several states that allow some exclusive operations on each of them.
I'm using traits instead of an enum to allow further customizations.
So, I'm able to use this pattern until I try to include it inside a struct (the Session part) that is mutated when files are added, changed or removed.
trait IssueState {}
struct Open;
impl IssueState for Open {}
struct WIP {
elapsed_time: u32,
}
impl IssueState for WIP {}
struct Closed {
elapsed_time: u32,
}
impl IssueState for Closed {}
struct Issue<T: IssueState + ?Sized> {
state: Box<T>,
comments: Vec<String>,
}
impl<T: IssueState> Issue<T> {
pub fn comment<S: Into<String>>(&mut self, comment: S) -> &mut Self {
self.comments.push(comment.into());
self
}
}
impl Issue<Open> {
pub fn new() -> Self {
Self {
state: Box::new(Open),
comments: vec![],
}
}
pub fn start(self) -> Issue<WIP> {
Issue {
state: Box::new(WIP { elapsed_time: 0 }),
comments: self.comments,
}
}
}
impl Issue<WIP> {
pub fn work(&mut self, time: u32) -> &mut Self {
self.state.elapsed_time += time;
self
}
pub fn done(self) -> Issue<Closed> {
let elapsed_time = self.state.elapsed_time;
Issue {
state: Box::new(Closed { elapsed_time }),
comments: self.comments,
}
}
}
impl Issue<Closed> {
pub fn elapsed(&self) -> u32 {
self.state.elapsed_time
}
}
struct Session<T: IssueState> {
user: String,
current_issue: Issue<T>,
}
impl<T: IssueState> Session<T> {
pub fn new<S: Into<String>>(user: S, issue: Issue<T>) -> Self {
Self {
user: user.into(),
current_issue: issue,
}
}
pub fn comment<S: Into<String>>(&mut self, comment: S) {
self.current_issue.comment(comment);
}
}
impl Session<WIP> {
pub fn work(&mut self, time: u32) {
self.current_issue.work(time);
}
}
trait Watcher {
fn watch_file_create(&mut self);
fn watch_file_change(&mut self);
fn watch_file_delete(&mut self);
}
impl<T: IssueState> Watcher for Session<T> {
fn watch_file_create(&mut self) {
self.current_issue = Issue::<Open>::new();
}
fn watch_file_change(&mut self) {}
fn watch_file_delete(&mut self) {}
}
fn main() {
let open = Issue::<Open>::new();
let mut wip = open.start();
wip.work(10).work(30).work(60);
let closed = wip.done();
println!("Elapsed {}", closed.elapsed());
let mut session = Session::new("Reviewer", closed);
session.comment("It is OK");
session.watch_file_create();
}
Rust Playground (original)
Rust Playground (edited)
What can I do to fix the problems?
Is the typestate pattern limited to only some situations that do not depend a lot on external events? I mean, I'm trying to use it for processing events, but is it a dead end?, why?
Your Session has a Issue<dyn IssueState> member, but you want to implement its work method by calling Issue<WIP>'s work method. The compiler complains, because an Issue<dyn IssueState> is not (necessarily) a Issue<WIP> and so does not implement that method.

how to solve cyclic-dependency & Iterator lifetime problem?

Rustaceans. when I start to write a BloomFilter example in rust. I found I have serveral problems have to solve. I struggle to solve them but no progress in a day. I need help, any suggestion will help me a lot, Thanks.
Problems
How to solve lifetime when pass a Iterator into another function?
// let bits = self.hash(value); // how to solve such lifetime error without use 'static storage?
// Below is a workaround code but need to computed in advanced.
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
How to solve cyclic-dependency between struts without modify lower layer code, e.g: bloom_filter ?
// cyclic-dependency:
// RedisCache -> BloomFilter -> Storage
// | ^
// ------------<impl>------------
//
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
Since rust does not have null value, How can I solve the cyclic-dependency initialization without any stubs?
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// I found can use Weak::new() to solve it,but need to downgrade a Rc reference.
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
Code
#![allow(unused)]
mod bloom_filter {
use std::{hash::Hash, marker::PhantomData};
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
// let bits = self.hash(value); // how to solve such lifetime error?
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
}
pub fn contains(&self, value: T) -> bool {
// lifetime problem same as Self::add(T)
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.contains_all(bits)
}
fn hash<'a, H: Hash + 'a>(&self, _value: H) -> Box<dyn Iterator<Item = u64> + 'a> {
todo!()
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands, RedisResult};
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
pub struct RedisCache<'a>(Client, RefCell<BloomFilter<&'a str>>);
impl<'a> RedisCache<'a> {
pub fn new() -> RedisCache<'a> {
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
return cache;
}
pub fn get(&mut self, key: &str, load_value: fn() -> Option<String>) -> Option<String> {
let filter = self.1.borrow();
if filter.contains(key) {
if let Ok(value) = self.0.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = self.0.set(key, &actual_value).unwrap();
return Some(actual_value);
}
}
return None;
}
}
impl<'a> Storage for RedisCache<'a> {
fn set(&mut self, bits: BitsIter) {
todo!()
}
fn contains_all(&self, bits: BitsIter) -> bool {
todo!()
}
}
}
Updated
First, thanks #Colonel Thirty Two give me a lot of information that I haven't mastered and help me fixed the problem of the iterator lifetime.
The cyclic-dependency I have solved by break the responsibility of the Storage into another struct RedisStorage without modify the bloom_filter module, but make the example bloated. Below is their relationships:
RedisCache -> BloomFilter -> Storage <---------------
| |
|-------> redis::Client <- RedisStorage ---<impl>---
I realized the ownership & lifetime system is not only used by borrow checker, but also Rustaceans need a bigger front design to obey the rules than in a GC language, e.g: java. Am I right?
Final Code
mod bloom_filter {
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
};
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
#[allow(unused)]
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
self.0.set(self.hash(value));
}
pub fn contains(&self, value: T) -> bool {
self.0.contains_all(self.hash(value))
}
fn hash<'a, H: Hash + 'a>(&self, value: H) -> BitsIter<'a> {
Box::new(
[3, 11, 31, 71, 131]
.into_iter()
.map(|salt| SimpleHasher(0, salt))
.map(move |mut hasher| hasher.hash(&value)),
)
}
}
struct SimpleHasher(u64, u64);
impl SimpleHasher {
fn hash<H: Hash>(&mut self, value: &H) -> u64 {
value.hash(self);
self.finish()
}
}
impl Hasher for SimpleHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
self.0 += bytes.iter().fold(0u64, |acc, k| acc * self.1 + *k as u64)
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands};
use std::{cell::RefCell, rc::Rc};
pub struct RedisCache<'a>(Rc<RefCell<Client>>, BloomFilter<&'a str>);
impl<'a> RedisCache<'a> {
pub fn new(client: Rc<RefCell<Client>>, filter: BloomFilter<&'a str>) -> RedisCache<'a> {
RedisCache(client, filter)
}
pub fn get<'f>(
&mut self,
key: &str,
load_value: fn() -> Option<&'f str>,
) -> Option<String> {
if self.1.contains(key) {
let mut redis = self.0.as_ref().borrow_mut();
if let Ok(value) = redis.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = redis.set(key, &actual_value).unwrap();
return Some(actual_value.into());
}
}
return None;
}
}
struct RedisStorage(Rc<RefCell<Client>>);
const BLOOM_FILTER_KEY: &str = "bloom_filter";
impl Storage for RedisStorage {
fn set(&mut self, bits: BitsIter) {
bits.for_each(|slot| {
let _: bool = self
.0
.as_ref()
.borrow_mut()
.setbit(BLOOM_FILTER_KEY, slot as usize, true)
.unwrap();
})
}
fn contains_all(&self, mut bits: BitsIter) -> bool {
bits.all(|slot| {
self.0
.as_ref()
.borrow_mut()
.getbit(BLOOM_FILTER_KEY, slot as usize)
.unwrap()
})
}
}
#[test]
fn prevent_cache_penetration_by_bloom_filter() {
let client = Rc::new(RefCell::new(Client::open("redis://localhost").unwrap()));
redis::cmd("FLUSHDB").execute(&mut *client.as_ref().borrow_mut());
let mut filter: BloomFilter<&str> = BloomFilter::by(Box::new(RedisStorage(client.clone())));
assert!(!filter.contains("Rust"));
filter.add("Rust");
assert!(filter.contains("Rust"));
let mut cache = RedisCache::new(client, filter);
assert_eq!(
cache.get("Rust", || Some("System Language")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Rust", || panic!("must never be called after cached")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Go", || panic!("reject to loading `Go` from external storage")),
None
);
}
}
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
In this case, the object in the box must be valid for the 'static lifetime. This isn't the case for the iterator returned by hash - its limited to the lifetime of self.
Try replacing with:
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
Or using generics instead of boxed trait objects.
So your RedisClient needs a BloomFilter, but the BloomFilter also needs the RedisClient?
Your BloomFilter should not use the RedisCache that itself uses the BloomFilter - that's a recipe for infinitely recursing calls (how do you know what calls to RedisCache::add should update the bloom filter and which calls are from the bloom filter?).
If you really have to, you need some form of shared ownership, like Rc or Arc. Your BloomFilter will also need to use a weak reference, or else the two objects will refer to each other and will never free.

Can I iterate over all the table items with FlatBuffers?

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.

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(())
}

Resources