Comparison between two Rc<RefCell<dyn Obj>> - Unconsistent behavior - rust

I'm playing with Rc<RefCell<dyn Obj>> and came up with a behavior I don't understand.
Basically, in a struct, I own a collection of Rc<RefCell<dyn Obj>>. I can push an item of type Concrete implementing Obj in the collection, and get a Rc<RefCell<Concrete>> of it. Then I need functions to test whether a given Rc<RefCell<Concrete>> or a given Rc<RefCell<dyn Obj>> belongs to the collection (not the value, the refcell !).
I came up with the following playground :
use std::{rc::Rc, cell::RefCell};
// Trait and implementing concrete type
pub trait Obj {}
struct Concrete {}
impl Obj for Concrete {}
// Structure owning a collection of Rc<RefCell<dyn Obj>>
struct V {
v: Vec<Rc<RefCell<dyn Obj>>>
}
impl V {
fn new() -> Self {
V{v: Vec::new()}
}
// Push a an item in the collection and get a Rc<RefCell<T>> to manipulate it
fn push<T: Obj + 'static>(&mut self, obj: T) -> Rc<RefCell<T>> {
let obj = Rc::new(RefCell::new(obj));
self.v.push(Rc::clone(&obj) as Rc<RefCell<dyn Obj>>);
obj
}
// Check whether a Rc<RefCell<T:Obj>> is in the collection
fn has_concrete_obj<T: Obj + 'static>(&self, candidate: &Rc<RefCell<T>>) -> bool {
for obj in self.v.iter() {
if Rc::ptr_eq(&obj, &(Rc::clone(candidate) as Rc<RefCell<dyn Obj>>)) {
return true;
}
}
false
}
// Check whether a Rc<RefCell<dyn Obj>> is in the collection
fn has_dyn_obj(&self, candidate: &Rc<RefCell<dyn Obj>>) -> bool {
for obj in self.v.iter() {
if Rc::ptr_eq(&obj, &candidate) {
return true;
}
}
false
}
}
fn main() {
let mut v = V::new();
let obj = v.push(Concrete{});
// here, we could use obj with obj.borrow().fn_conrete() or obj.borrow_mut().fn_concrete_mut()
// Basic tests that should pass
assert!(v.has_concrete_obj(&obj));
assert!(v.has_dyn_obj(&(Rc::clone(&obj) as Rc<RefCell<dyn Obj>>)));
assert!(v.has_dyn_obj(v.v.iter().next().unwrap()));
}
It works as intended in the playground (all asserts pass), but not anymore when I run the exact same sample code on my computer : the second assert fails, whereas the first and the third pass. I don't get why, the first and the second doing basically pretty much the same thing...

Related

Derive macro generation

I'm making my own Serializable trait, in the context of a client / server system.
My idea was that the messages sent by the system is an enum made by the user of this system, so it can be customize as needed.
Too ease implementing the trait on the enum, I would like to use the #[derive(Serializable)] method, as implementing it is always the same thing.
Here is the trait :
pub trait NetworkSerializable {
fn id(&self) -> usize;
fn size(&self) -> usize;
fn serialize(self) -> Vec<u8>;
fn deserialize(id: usize, data: Vec<u8>) -> Self;
}
Now, I've tried to look at the book (this one too) and this example to try to wrap my head around derive macros, but I'm really struggling to understand them and how to implement them. I've read about token streams and abstract trees, and I think I understand the basics.
Let's take the example of the id() method : it should gives a unique id for each variant of the enum, to allow headers of messages to tell which message is incoming.
let's say I have this enum as a message system :
enum NetworkMessages {
ErrorMessage,
SpawnPlayer(usize, bool, Transform), // player id, is_mine, position
MovePlayer(usize, Transform), // player id, new_position
DestroyPlayer(usize) // player_id
}
Then, the id() function should look like this :
fn id(&self) -> usize {
match &self {
&ErrorMessage => 0,
&SpawnPlayer => 1,
&MovePlayer => 2,
&DestroyPlayer => 3,
}
}
Here was my go with writting this using a derive macro :
#[proc_macro_derive(NetworkSerializable)]
pub fn network_serializable_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_network_serializable_macro(&ast)
}
fn impl_network_serializable_macro(ast: &syn::DeriveInput) -> TokenStream {
// get enum name
let ref name = ast.ident;
let ref data = ast.data;
let (id_func, size_func, serialize_func, deserialize_func) = match data {
// Only if data is an enum, we do parsing
Data::Enum(data_enum) => {
// Iterate over enum variants
let mut id_func_internal = TokenStream2::new();
let mut variant_id: usize = 0;
for variant in &data_enum.variants {
// add the branch for the variant
id_func_internal.extend(quote_spanned!{
variant.span() => &variant_id,
});
variant_id += 1;
}
(id_func_internal, (), (), ())
}
_ => {(TokenStream2::new(), (), (), ())},
};
let expanded = quote! {
impl NetworkSerializable for #name {
// variant_checker_functions gets replaced by all the functions
// that were constructed above
fn size(&self) -> usize {
match &self {
#id_func
}
}
/*
#size_func
#serialize_func
#deserialize_func
*/
}
};
expanded.into()
}
So this is generating quite a lot of errors, with the "proc macro NetworkSerializable not expanded: no proc macro dylib present" being first. So I'm guessing there a lot of misunderstaning from my part in here.

Cannot get wrapping of filter to compile

I have the goal of wrapping an Iterator<Item = rusb::Device<_> to Iterator<Item = LitraDevice>. The latter contains specific implementation.
To make this work I tried the following code:
use std::iter::Filter;
use rusb;
const VENDOR: u16 = 0x046d;
const PRODUCT: u16 = 0xc900;
struct LitraDevice {
dev: rusb::Device<rusb::GlobalContext>,
}
pub struct LitraDevices {
unfiltered: rusb::DeviceList<rusb::GlobalContext>,
}
struct LitraDeviceIterator<'a> {
it: Filter<rusb::Devices<'a, rusb::GlobalContext>, for<'r> fn(&'r rusb::Device<rusb::GlobalContext>) -> bool>,
}
impl LitraDevices {
pub fn new() -> Self {
let unfiltered = rusb::devices().unwrap();
LitraDevices { unfiltered }
}
fn can_not_handle<'r>(dev: &'r rusb::Device<rusb::GlobalContext>) -> bool {
let desc = dev.device_descriptor().unwrap();
match (desc.vendor_id(), desc.product_id()) {
(VENDOR, PRODUCT) => (),
_ => return true,
}
match desc.class_code() {
LIBUSB_CLASS_HID => return true, // Skip HID devices, they are handled directly by OS libraries
_ => return false,
}
}
pub fn iter<'a>(self) -> LitraDeviceIterator<'a> {
let it = self.unfiltered.iter().filter(Self::can_not_handle);
LitraDeviceIterator{
it,
}
}
}
impl <'a> Iterator for LitraDeviceIterator<'a> {
type Item = LitraDevice;
fn next(&mut self) -> Option<Self::Item> {
let n = self.it.next();
match n {
Some(Device) => return Some(LitraDevice{dev: n.unwrap()}),
None => return None,
}
}
}
Now I really cannot figure out how to code LitraDeviceIterator so that it wraps the filtered iterator.
All code iterations I have tried so far turn into a generic nightmare very quickly.
I rewrote your iter() to yield LitraDevice, you can surely take it wherever you wanted to go from there.
The first underlying issue is that filter() yields references, but in cases like these, you actually mean to move yielded items while filtering. That's what filter_map() is capable of. That way, you can scrap the references, greatly simplifying your code.
(This code does not work yet, read on)
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
self.unfiltered.iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}
Now, there's a second little issue at play her: rusb::DeviceList<T : UsbContext>>::iter(&self) returns rusb::Devices<'_, T>, '_ being the anonymous lifetime inferred from &self. Meaning, while you can drive rusb::Devices<'_, T> to yield Device<T>s, you can not actually keep it around longer than self.unfiltered. More specifically, as you consume self in iter(), you can not return an iterator referencing that rusb::Devices<'_, T> from iter(). One solution is to immediately collect, then again moving into an iterator.
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
let devices = self.unfiltered.iter().collect::<Vec<_>>();
devices.into_iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}

Function that generates a HashMap of Enum variants

I'm working with apollo_parser to parse a GraphQL query. It defines an enum, apollo_parser::ast::Definition, that has several variants including apollo_parser::ast::OperationDefintion and apollo_parser::ast::FragmentDefinition. I'd like to have a single Trait I can apply to apollo_parser::ast::Definition that provides a function definition_map that returns a HashMap mapping the operation name to the variant instance.
I've got as far as the trait, but I don't know how to implement it. Also, I don't know how to constrain T to be a variant of Definition.
trait Mappable {
fn definition_map<T>(&self) -> HashMap<String, T>;
}
EDIT:
Here's a Rust-ish pseudocode implementation.
impl Mappable for Document {
fn definition_map<T>(&self) -> HashMap<String, T> {
let defs = Vec<T> = self.definitions
.filter_map(|def: Definition| match def {
T(foo) => Some(foo),
_ => None
}).collect();
let map = HashMap::new();
for def: T in definitions {
map.insert(def.name(), def);
}
map
}
}
and it would output
// From a document consisting of OperationDefinitions "operation1" and "operation2"
// and FragmentDefinitons "fragment1" and "fragment2"
{
"operation1": OperationDefinition(...),
"operation2": OperationDefinition(...),
}
{
"fragment1": FragmentDefinition(...),
"fragment2": FragmentDefinition(...)
}
I don't know how to constrain T to be a variant of Definition.
There is no such thing in Rust. There's the name of the variant and the name of the type contained within that variant, there is no relationship between the two. The variants can be named whatever they want, and multiple variant can contain the same type. So there's no shorthand for pulling a T out of an enum which has a variant with a T.
You need to make your own trait that says how to get a T from a Definition:
trait TryFromDefinition {
fn try_from_def(definition: Definition) -> Option<Self> where Self: Sized;
fn name(&self) -> String;
}
And using that, your implementation is simple:
impl Mappable for Document {
fn definition_map<T: TryFromDefinition>(&self) -> HashMap<String, T> {
self.definitions()
.filter_map(T::try_from_def)
.map(|t| (t.name(), t))
.collect()
}
}
You just have to define TryFromDefinition for all the types you want to use:
impl TryFromDefinition for OperationDefinition {
fn try_from_def(definition: Definition) -> Option<Self> {
match definition {
Definition::OperationDefinition(operation) => Some(operation),
_ => None,
}
}
fn name(&self) -> String {
self.name().unwrap().ident_token().unwrap().text().into()
}
}
impl TryFromDefinition for FragmentDefinition {
fn try_from_def(definition: Definition) -> Option<Self> {
match definition {
Definition::FragmentDefinition(operation) => Some(operation),
_ => None,
}
}
fn name(&self) -> String {
self.fragment_name().unwrap().name().unwrap().ident_token().unwrap().text().into()
}
}
...
Some of this could probably be condensed using macros, but there's no normalized way that I can tell to get a name from a definition, so that would still have to be custom per type.
You should also decide how you want to handle definitions that don't have a name; you'd probably want to return Option<String> to avoid all those .unwrap()s, but I don't know how you'd want to put that in your HashMap.
Without knowing your whole workflow, I might suggest a different route instead:
struct Definitions {
operations: HashMap<String, OperationDefinition>,
fragments: HashMap<String, FragmentDefinition>,
...
}
impl Definitions {
fn from_document(document: &Document) -> Self {
let mut operations = HashMap::new();
let mut fragments = HashMap::new();
...
for definition in document.definitions() {
match definition {
Definition::OperationDefinition(operation) => {
let name: String = operation.name().unwrap().ident_token().unwrap().text().into();
operations.insert(name, operation);
},
Definition::FragmentDefinition(fragment) => {
let name: String = fragment.fragment_name().unwrap().name().unwrap().ident_token().unwrap().text().into();
fragments.insert(name, fragment);
},
...
}
}
Definitions {
operations,
fragments,
...
}
}
}

How do I create a Vec<T> where T: Into<_> in Rust?

This is my example code. I am trying to pass a Vec<T> to a function where T: Into<_>!
enum Test {
FN(Box<dyn Fn()>),
STR(String),
}
impl<F> From<F> for Test
where F: Fn() + 'static
{
fn from(f: F) -> Self {
Self::FN(Box::new(f))
}
}
impl From<String> for Test {
fn from(s: String) -> Self {
Self::STR(s)
}
}
fn main() {
into(vec![
|| println!("func 1"),
|| println!("func 2"),
String::from("string 1"),
]);
}
fn into<T>(v: Vec<T>)
where T: Into<Test>
{
for test in v {
let test = test.into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The error is at the second closure:
expected closure, found a different closure
The problem is that Into<_> can't be dyn because it is Sized, so that doesn't work!
I am hoping for an output of:
func 1
func 2
string 1
Any answers or ideas?!
Rust does not generally do type coercion automatically. You've defined your From implementations, but nothing is calling them. You'd need to change your function to be more along the lines of
fn main() {
into(vec![
Test::from(|| println!("func 1")),
Test::from(|| println!("func 2")),
Test::from(String::from("string 1")),
]);
}
Just because you create a Test enum does not mean that Rust will reconcile the type of your otherwise heterogenous vector to be Test. You must manually instantiate each enum variant (and put a Box around your closures):
fn main() {
let x: Vec<Test> = vec![
Test::FN(Box::new(|| println!("func 1"))),
Test::FN(Box::new(|| println!("func 2"))),
Test::STR(String::from("string 1")),
];
into(x);
}
Your idea is to have a Vec of objects all being convertable to test. Yet Vec requires objects of the same type:
each closure has a different type
String is different from closure types
An example with a Vec with elements of the same type could be a Vecof just one of your elements:
into(vec![|| println!("func 1")]);
into(vec![|| println!("func 2")]);
into(vec![String::from("string 1")]);
// each has one element of ONE type, this compiles and runs
or a Vec of multiple elements of the same type:
into(vec![String::from("string 1"), String::from("string 2")]);
// each has multiple element of ONE type (String), this compiles and runs
To get your example to compile you will have to wrap your items in a wrapper type (e.g. an enum) that implements Into<Test>.
Your concrete example already contains such a wrapper type (Test) and thus your example unfortunately gets trivial, because if you put already Tests in your Vec you will not have to call into on them any more (this is shown in the other examples).
Thank you for all the answers,
I found my own solution by creating my own MyInto trait:
trait MyInto {
fn my_into(&self) -> Test;
}
enum Test<'l> {
FN(&'l dyn Fn()),
STR(String),
}
impl<F> MyInto for F
where F: Fn() + 'static
{
fn my_into(&self) -> Test {
Test::FN(self)
}
}
impl MyInto for String {
fn my_into(&self) -> Test {
Test::STR(self.to_owned())
}
}
fn main() {
into(vec![
&|| println!("func 1"),
&|| println!("func 2"),
&String::from("string 1"),
]);
}
fn into(v: Vec<&dyn MyInto>) {
for test in v {
let test = test.my_into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The output is now:
func 1
func 2
string 1
It is now possible to use the dyn in &dyn MyInto, because MyInto is not Sized!

How to build a HashMap of Vectors in Rust?

I'm a Rust newbie. I'm trying to represent a directed graph's adjacency list as a HashMap of char {vertex name} to Vector of (char,int) {vertex name, cost}. I want the final HashMap to be immutable, but I'd like to build up the vector and then not need to make a copy of it to make it immutable.
My code is below. At the indicated line I get "cannot borrow immutable dereference (dereference is implicit, due to indexing) as mutable". This makes sense, as the Vec<(char,int)> in the map is not mutable. But I'm not sure how to fix it.
Is there a way to do this in Rust?
pub struct Edge {
to: char,
from: char,
weight: int
}
pub struct digraph {
_vertices: Vec<char>,
_adj_list: HashMap<char, Vec<(char,int)> >
}
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for node in (*nodes).iter() {
tmp_adj_list.insert(*node, Vec::new());
}
for edge in (*edges).iter() {
let Edge{ to: to, from:from, weight:weight } = *edge;
if !(*nodes).contains(&to) | !(*nodes).contains(&from) {
return None;
}
tmp_adj_list[from].push((to,weight)) // *********** error here
}
Some(digraph { _vertices: (*nodes).clone(), _adj_list: tmp_adj_list })
}
}
Taking [] onto a HashMap is sugar for the (now deprecated) get(..) function, which declaration is :
fn get<'a>(&'a self, k: &K) -> &'a V
and returns a constant (&) reference. But the push(..) method of Vec expects a &mut reference, hence the error.
What you need is the get_mut(..) method of HashMap, which returns a &mut reference to the value.
Also, some minor points:
when calling a method, dereference is automatic : (*foo).bar() is exactly the same as foo.bar()
you can dereference automatically in your loop with for &edge in edges.iter() {...}
Including all this, your function becomes :
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for &node in nodes.iter() {
tmp_adj_list.insert(node, Vec::new());
}
for &edge in edges.iter() {
let Edge{ to: to, from:from, weight:weight } = edge;
if !nodes.contains(&to) | !nodes.contains(&from) {
return None;
}
tmp_adj_list.get_mut(&from).push((to,weight))
}
Some(digraph { _vertices: nodes.clone(), _adj_list: tmp_adj_list })
}
}

Resources