I have a struct A which implements BorshDeserialize and BorshSerialize as follows
#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
struct A {
a : i32,
b: String,
}
I know I can serialize or deserialize A when I do the following:-
let s = A {a: 1 , b: "a".to_string()};
// Serialize
let serialzed_data = s.try_to_vec().unwrap()
// Deserialize
deserialized_struct = A::try_from_slice(&serialzed_data).unwrap();
I am trying to wrap over these two methods by creating two general traits on main.rs
where I import this struct from another file a.rs.
pub trait Serializable<T: BorshSerialize> {
fn serialize(s: T) -> Vec<u8> {
s.try_to_vec().unwrap()
}
}
pub trait Deserializable<T : BorshDeserialize> {
fn deserialize(s: &[u8]) -> Result<T, ()> {
let deserialized_val = match T::try_from_slice(&s) {
Ok(val) => {val},
Err(_) => {return Err(());},
};
Ok(deserialized_val)
}
}
where I implement Serialize and Deserialize for A as follows on a.rs
impl Serializable<A> for A {}
impl Deserializable<A> for A {}
But in the source code when I call the method serialize on A
for this instruction,
A::serialize(&some_instance_of_A).unwrap()
I get the following error
A::serialize(&some_instance_of_A).unwrap()
^^^^^^^^^ multiple `serialize` found
|
= note: candidate #1 is defined in an impl of the trait `Serializable` for the type `A`
= note: candidate #2 is defined in an impl of the trait `BorshSerialize` for the type `A`
help: disambiguate the associated function for candidate #1
|
46 | <&Self as A::Serializable>::serialize(&some_instance_of_A), // TODO. See issue #64
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: disambiguate the associated function for candidate #2
|
46 | <&A as BorshSerialize>::serialize(&some_instance_of_A).concat(), // TODO. See issue #64
|
I understand that the compiler gets confused by the two instances of serialization schemes created(one due to Borsh from derive macro and the other from Serialize trait on main.rs).
Is there a way to directly make the serialize call fall to BorshSerialize by default when A::serialize is called.
By preventing to import the BorshSerialize trait you can get rid of the error.
With only the Serializable trait in scope, only one method can be called:
#[derive(Clone, PartialEq, Eq, borsh::BorshSerialize, borsh::BorshDeserialize)]
struct A {
a : i32,
b: String,
}
impl Serializable for A {}
fn main() {
let a = A { a: 0, b: String::from("") };
let vec = a.serialize();
eprintln!("{:?}", vec);
}
pub trait Serializable: borsh::BorshSerialize {
fn serialize(&self) -> Vec<u8> {
self.try_to_vec().unwrap()
}
}
pub trait Deserializable<T : borsh::BorshDeserialize> {
fn deserialize(s: &[u8]) -> Result<T, ()> {
let deserialized_val = match T::try_from_slice(&s) {
Ok(val) => {val},
Err(_) => {return Err(());},
};
Ok(deserialized_val)
}
}
Related
In this code, I have the skeleton of an observable system. The documentation on implementing Observable and other decoupling patterns are usually missing a final step on allowing access to the listener while also having it be &mut during the notification call, but that's what RefCell is intended to handle. So I have this code all worked out, but I'm having a last piece of trouble getting my concrete T into the &dyn Trait.
use std::{cell::RefCell, rc::Rc};
pub trait Observer {
fn notify(&mut self);
}
#[derive(Default)]
pub struct Subject<'s> {
listeners: Vec<Rc<RefCell<Box<dyn Observer + 's>>>>,
}
pub fn wrap<T>(t: T) -> Rc<RefCell<Box<T>>> {
Rc::new(RefCell::new(Box::new(t)))
}
impl<'s> Subject<'s> {
pub fn add_observer(&mut self, observer: Rc<RefCell<Box<dyn Observer + 's>>>) {
self.listeners.push(observer)
}
pub fn notify(&mut self) {
for listener in &mut self.listeners {
listener.borrow_mut().notify();
}
}
}
#[cfg(test)]
mod test {
use super::{wrap, Observer, Subject};
#[derive(Default)]
pub struct Counter {
count: usize,
}
impl Observer for Counter {
fn notify(&mut self) {
self.count += 1;
}
}
#[test]
fn it_observes() {
let mut subject = Subject::default();
let counter = wrap(Counter::default());
subject.add_observer(counter); // mismatched types
for i in 1..5 {
subject.notify();
subject.notify();
assert_eq!(counter.borrow().count, i * 2);
}
}
}
The full error is
error[E0308]: mismatched types
--> src/observer.rs:48:30
|
48 | subject.add_observer(counter);
| ^^^^^^^ expected trait object `dyn Observer`, found struct `Counter`
|
= note: expected struct `Rc<RefCell<Box<(dyn Observer + 'static)>>>`
found struct `Rc<RefCell<Box<Counter>>>
I've seen (what looks like) this pattern used in a number of contexts, but I can't tell what either I'm missing or doing differently.
How do I get the T: Trait out of its static dispatch and into dynamic dispatch?
You can take to boxing outside of your wrap function, and box the counter itself with the proper box type:
pub fn wrap<T>(t: T) -> Rc<RefCell<T>> {
Rc::new(RefCell::new(t))
}
...
let counter: Box<dyn Observer> = Box::new(Counter::default());
let counter = wrap(counter);
Playground
Btw, once you have the dynamic dispatch, you have an dyn Observer so you lose access to the Counter itself. You will have to take ownership of it and downcast the pointer to the concrete type again.
Let's say I want to define my own type..
struct MyString(String);
Does Rust let me define the behavior when comparing the string against another type, such as an Option<MyString>? I want to write something like this,
impl std::cmp::PartialOrd<Option<MyString>> {
fn partial_cmp(self, other: Option<MyString> ) {
}
}
But I'm getting,
error[E0116]: cannot define inherent impl for a type outside of the crate where the type is defined [...] impl for type defined outside of crate. [...] define and implement a trait or new type instead
This is confusing to me because MyString is my type. Is this a violation of coherence?
Your syntax is incorrect. You also need to implment ParialEq because PartialCmp requires it:
#![allow(unused)]
use std::cmp::Ordering;
#[derive(Debug, PartialEq, Eq)]
struct MyString(String);
impl std::cmp::PartialOrd<Option<MyString>> for MyString {
fn partial_cmp(&self, other: &Option<MyString>) -> Option<Ordering> {
match other {
None => None,
Some(s) => s.0.partial_cmp(&self.0),
}
}
}
impl std::cmp::PartialEq<Option<MyString>> for MyString {
fn eq(&self, other: &Option<MyString>) -> bool {
match other {
Some(s) => s.eq(self),
None => false,
}
}
}
fn main() {
let a = MyString("foo".to_string());
println!("{:?}", a > None)
}
The error
impl for a type outside of the crate where the type is defined
Is because I left off for MyString in impl ... for MyString {}. An easy syntax error to make that can be fixed by adding that,
impl std::cmp::PartialOrd<Option<MyString>> for MyString {
fn partial_cmp(self, other: Option<MyString> ) {
`
Then I get the much more reasonable error
error[E0277]: can't compare `MyString` with `Option<MyString>`
--> src/main.rs:6:6
|
6 | impl std::cmp::PartialOrd<Option<MyString>> for MyString {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `MyString == Option<MyString>`
|
= help: the trait `PartialEq<Option<MyString>>` is not implemented for `MyString`
I am writing a struct that functions as a thin wrapper over an existing struct. The existing struct isn't fixed, so I've written it as a type parameter (see struct B below). I would like B to preserve convertibility (i.e. From/Into) based on the internal wrapped type, i.e. if A1 is convertible to A then B<A1> should be convertible to B<A> as well.
I tried the following code:
pub struct A {}
pub struct A1 {}
impl From<A1> for A {
fn from(a1: A1) -> Self {
Self {}
}
}
pub struct B<T> {
t: T,
other_stuff: String,
}
impl<T, U: Into<T>> From<B<U>> for B<T> {
fn from(b: B<U>) -> Self {
Self {
t: b.t.into(),
other_stuff: b.other_stuff,
}
}
}
pub fn main() {
// I would like this to work:
let ba1: B<A1> = B{ t: A1{}, other_stuff: "abc".to_owned() };
let ba: B<A> = ba1.into();
}
It produces a compilation error:
error[E0119]: conflicting implementations of trait `std::convert::From<B<_>>` for type `B<_>`:
--> src/main.rs:13:1
|
13 | impl<T, U: Into<T>> From<B<U>> for B<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
I think I understand why the error arises (because converting B<A> to B<A> is already defined), but how may I rewrite my code to avoid the error?
I am applying the polymorphism solution in Rust to my problem. I would like to use this solution with Box<_> as it seems the most straight and simple, but it doesn't work.
#[derive(Clone, Copy)]
pub struct NewPost;
#[derive(Clone, Copy)]
pub struct Post;
#[derive(Clone, Copy)]
pub struct PgConnection;
#[derive(Clone, Copy)]
pub struct DBPost;
pub trait DBAdapter {
fn create(self, post: NewPost) -> Post;
fn read(self) -> Vec<Post>;
}
impl DBPost {
// DATABASE classes
pub fn establish_connection(self) -> PgConnection {
unimplemented!()
}
}
impl DBAdapter for DBPost {
fn create(self, _post: NewPost) -> Post {
unimplemented!()
}
fn read(self) -> Vec<Post> {
unimplemented!()
}
}
struct GetPostsCase {
db: Box<dyn DBAdapter>,
}
impl GetPostsCase {
pub fn new(db: Box<dyn DBAdapter>) -> GetPostsCase {
GetPostsCase { db: db }
}
pub fn run(&self) -> Vec<Post> {
let result = self.db.read();
result
}
}
The error is:
error[E0161]: cannot move a value of type dyn DBAdapter: the size of dyn DBAdapter cannot be statically determined
--> src/lib.rs:45:22
|
45 | let result = self.db.read();
| ^^^^^^^
error[E0507]: cannot move out of `*self.db` which is behind a shared reference
--> src/lib.rs:45:22
|
45 | let result = self.db.read();
| ^^^^^^^ move occurs because `*self.db` has type `dyn DBAdapter`, which does not implement the `Copy` trait
Your read method takes the (unsized) value instead of taking a reference (whose size is always the same).
You can solve the problem by changing the contract of DBAdapter
from
fn read(self) -> Vec<Post> {
to
fn read(&self) -> Vec<Post> {
// ^--- added the ampersand
(depending on your implementation you might need &mut)
I want to clone head which is a Box<Node<T>>:
let mut node = Some((*head).clone());
Here is the full code (playground):
use std::boxed::Box;
pub struct List<T> {
pub head: Option<Box<Node<T>>>,
pub size: u64,
}
impl<T> List<T> {
pub fn new() -> List<T> {
return List {
head: Option::None,
size: 0,
};
}
pub fn push_back(&mut self, data: T) {
match &self.head {
Some(head) => {
let mut node = Some((*head).clone());
while (*(node).unwrap()).next.is_some() {
node = (*node.unwrap()).next;
}
node.unwrap().next = Some(Box::new(Node::new(data)));
}
None => {
self.head = Some(Box::new(Node::new(data)));
}
}
}
}
#[derive(Clone)]
pub struct Node<T> {
pub next: Option<Box<Node<T>>>,
pub value: T,
}
impl<T> Node<T> {
pub fn new(v: T) -> Node<T> {
Node {
next: Option::None,
value: v,
}
}
}
The compiler keeps saying the method clone exists but the following trait bounds were not satisfied:
error[E0599]: no method named `clone` found for type `std::boxed::Box<Node<T>>` in the current scope
--> src/lib.rs:19:45
|
19 | let mut node = Some((*head).clone());
| ^^^^^
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`Node<T> : std::clone::Clone`
`std::boxed::Box<Node<T>> : std::clone::Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `std::clone::Clone`
I tried to add #[derive(Clone)] but it still doesn't work:
#[derive(Clone)]
pub struct Node<T> {
pub next: Option<Box<Node<T>>>,
pub value: T
}
How can I do this?
A reproduction of the error:
#[derive(Clone)]
pub struct Node<T> {
pub next: Option<Box<Node<T>>>,
pub value: T,
}
fn thing<T>(node: Node<T>) {
node.clone();
}
error[E0599]: no method named `clone` found for type `Node<T>` in the current scope
--> src/lib.rs:8:10
|
2 | pub struct Node<T> {
| ------------------ method `clone` not found for this
...
8 | node.clone();
| ^^^^^
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`Node<T> : std::clone::Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `std::clone::Clone`
You need to add a trait bound that says that T implements Clone:
fn thing<T>(node: Node<T>)
where
T: Clone,
{
node.clone();
}
See also:
Deriving a trait results in unexpected compiler error, but the manual implementation works
Your code has numerous non-idiomatic aspects:
unneeded import of std::boxed::Box
unneeded unwraps
unneeded dereferences.
You don't even need clone here, and it's probably incorrect to use it. I'd write:
pub fn push_back(&mut self, data: T)
where
T: Clone,
{
let spot = match &mut self.head {
Some(head) => {
let mut node = &mut head.next;
while let Some(n) = node {
node = &mut n.next;
}
node
}
None => &mut self.head,
};
*spot = Some(Box::new(Node::new(data)));
}
See also:
Adding an append method to a singly linked list