Rust define trait interface for any type? - serialization

I am building a rendering engine, one thing I want is to handle mangagement of arbitrary mesh data, regardless of representation.
My idea was, define a trait the enforces a function signature and then serialization can be handled by the user while I handle all the gpu stuff. This was the trait I made:
pub enum GpuAttributeData
{
OwnedData(Vec<Vec<i8>>, Vec<u32>),
}
pub trait GpuSerializable
{
fn serialize(&self) -> GpuAttributeData;
}
So very simple, give me a couple of arrays.
When i tested things inside the crate it worked, but I moved my example outside the crate, i.e. I have this snippet in an example:
impl <const N : usize> GpuSerializable for [Vertex; N]
{
fn serialize(&self) -> GpuAttributeData
{
let size = size_of::<Vertex>() * self.len();
let data = unsafe {
let mut data = Vec::<i8>::with_capacity(size);
copy_nonoverlapping(
self.as_ptr() as *const i8, data.as_ptr() as *mut i8, size);
data.set_len(size);
data
};
// let indices : Vec<usize> = (0..self.len()).into_iter().collect();
let indices = vec![0, 1, 2];
let mut buffers :Vec<Vec<i8>> = Vec::new();
buffers.push(data);
return GpuAttributeData::OwnedData(buffers, indices);
}
}
Which gives me this error:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> examples/01_spinning_triangle/main.rs:41:1
|
41 | impl <const N : usize> GpuSerializable for [Vertex; N]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------
| | |
| | this is not defined in the current crate because arrays are always foreign
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
This utterly breaks my design. The whole point of what I am trying to achieve is, anyone anywhere should be able to implement that trait, inside or outside any crate, to be able to serialize whatever data they have, in whatever esoteric format it is.
Can I somehow bypass this restriction? If not, is there another way I could enforce at runtime "give me an object that has this function signature among its methods"?

Rust has the orphan rule, which says that any implementation of a trait on a type must exist in the same crate as at least one of the trait or the type. In other words, both types can't be foreign. (It's a bit more complex than this -- for example, you can implement a foreign generic trait on a foreign type if a generic type argument to the generic trait is a type declared in the local crate.)
This is why you frequently see so-called "newtypes" in Rust, which are typically unit structs with a single member, whose sole purpose is to implement a foreign trait on a foreign type. The newtype lives in the same crate as the implementation, so the compiler accepts the implementation.
This could be realized in your example with a newtype around the array type:
#[repr(transparent)]
struct VertexArray<const N: usize>(pub [Vertex; N]);
impl<const N: usize> Deref for VertexArray<N> {
type Target = [Vertex; N];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<const N: usize> DerefMut for VertexArray<N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<const N: usize> GpuSerializable for VertexArray<N> {
// ...
}
Note that because of #[repr(transparent)], the layout of both VertexArray<N> and [Vertex; N] are guaranteed to be identical, meaning you can transmute between them, or references to them. This allows you to, for example, reborrow a &[Vertex; N] as a &VertexArray<N> safely, which means you can store all of your data as [Vertex; N] and borrow it as the newtype at zero cost whenever you need to interact with something expecting an implementation of GpuSerializable.
impl<const N: usize> AsRef<VertexArray<N>> for [Vertex; N] {
fn as_ref(&self) -> &VertexArray<N> {
unsafe { std::mem::transmute(self) }
}
}

Related

is `as_ref` rust's ways to implement idiomatic generic?

As I understand it, rust is a "has a" and not a "is a" language (composition over inheritance).
this makes Liskov substitutions slightly more complicated but not impossible using Traits. While I can use LSP, it appears to not be the idiomatic way of implementing type coercion in rust. I'm left confused of how to operate.
minimal example
Let's assume I have two structs
struct Real(i32);
struct Complex(Real, Real);
And a function project which takes a Complex and return a projection of the input.
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
// we pass by reference because we need to be blazingly fast
fn project(c : &Complex) -> Complex {
Complex(c.0, Real(0))
}
fn main() {
let a = Complex(Real(1), Real(2));
let x = project(&a);
println!("{} + {}i", x.0.0, x.1.0)
}
To keep things simple, please assume we are the situation in which we benefit from passing Real by reference and project should not be duplicated as multiple implementation from a trait for Real and Complex.
Assume we expect to also use project on Reals from time to time.
Making project somewhat generic
My OOP instincts pushes me to make some supertype for Real and Complex, let's say the trait AsReal
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
trait AsReal {
fn as_real(&self) -> Real;
}
impl AsReal for Real { fn as_real(&self) -> Real { *self } }
impl AsReal for Complex { fn as_real(&self) -> Real { self.0 } }
fn project (r : &impl AsReal) -> Complex {
Complex( r.as_real(), Real(0) )
}
fn main() {
let a = Real(1);
let b = Complex(Real(2), Real(3));
let x = project(&a);
let y = project(&b);
println!("{} + {}i", x.0.0, x.1.0);
println!("{} + {}i", y.0.0, y.1.0);
}
But apparently, the rusty way would be to use AsRef<Real> instead
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
fn project<U: AsRef <Real>>(r : U) -> Complex {
Complex ( *r.as_ref(), Real(0) )
}
impl AsRef<Real> for Complex {
fn as_ref(&self) -> &Real { &self.0 }
}
impl AsRef<Real> for Real {
fn as_ref(&self) -> &Real { self }
}
fn main() {
let a = Real(1);
let b = Complex(Real(2), Real(3));
let x = project(&a);
let y = project(&b);
println!("{} + {}i", x.0.0, x.1.0);
println!("{} + {}i", y.0.0, y.1.0);
}
Which leaves me unsatisfied : the prototype for project became very wordy and hard to read. So much so it feels like the convenience of use for project is simply not worth it.
Furthermore, it means the function must opt-in for Complex into Real coercion and I dislike that notion as it feel like it pushes me to develop defensively and use AsRef<...> all the time.
I don't feel like I have the full picture, what would be the idiomatic way to interact with rust for situation like this ?
Based on your description, it seems like you could go with this:
project takes a Real
Complex provides an into_real() method that returns a Real
Small sidenote: if your types are small and Copy, a pointer isn't always faster. Compiler explorer can be a great tool for showing you what the assembly for a snippet is/
That being said, I'd write it like this.
fn project(real: Real) -> Real {
// very complex logic
}
// deriving Copy makes these types behave more like numbers
#[derive(Copy, Clone)]
struct Real(i32);
#[derive(Copy, Clone)]
struct Complex(Real, Real);
impl Complex {
fn into_real(self) -> Real {
self.0
}
}
fn main() {
let real = Real(0);
let complex = Complex(Real(0), Real(0));
project(real);
project(complex.into_real());
}
If you really hate having to write into_real(), you could make the call-site simpler and make the declaration-site more complex by:
implementing From<Complex> for Real (though arguably this needs its own trait since there's more than one way to get a Real from a Complex)
making project accept an impl Into<Real>
impl From<Complex> for Real {
fn from(c: Complex) {
c.0
}
}
fn project(real: impl Into<Real>) {
let real = real.into();
// real is a `Real` here
}
Though honestly, I'd just go for the first option. Your function doesn't really need to be generic, and that increases monomorphization cost. It's not very OOP, but Rust is not an OOP language.

Deserialize a Vec of values into a struct by implementing serde `Deserializer`

I have a data format using custom enum of values. From the database I receive a Vec<MyVal>. I want to convert this to a struct (and fail if it doesn't work). I want to use serde because after processing I want to return the API response as a json, and serde makes this super easy.
Playground link for the example
enum MyVal {
Bool(bool),
Text(String)
}
#[derive(Serialize, Deserialize)]
struct User {
name: String,
registered: bool
}
The challenge is with converting the data format into the serde data model. For this I can implement a Deserializer and implement the visit_seq method i.e. visit the Vec<MyVal> as if it were a sequence and return the values one by one. The visitor for User can consume the visited values to build the struct User.
However I'm not able to figure out how to convert the Vec into something visitor_seq can consume. Here's some sample code.
struct MyWrapper(Vec<MyVal>);
impl<'de> Deserializer<'de> for MyWrapper {
type Error = de::value::Error;
// skip unncessary
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let convert_myval = move |myval: &MyVal| match myval {
MyVal::Bool(b) => visitor.visit_bool(*b),
MyVal::Text(s) => visitor.visit_string(s.clone())
};
// now I have a vec of serde values
let rec_vec: Vec<Result<V::Value, Self::Error>> =
self.0.iter().map(|myval| convert_myval(myval)).collect();
// giving error!!
visitor.visit_seq(rec_vec.into_iter())
}
}
The error is
92 | visitor.visit_seq(rec_vec.into_iter())
| --------- ^^^^^^^^^^^^^^^^^^^ the trait `SeqAccess<'de>` is not implemented for `std::vec::IntoIter<Result<<V as Visitor<'de>>::Value, _::_serde::de::value::Error>>`
| |
| required by a bound introduced by this call
So I looked into SeqAccess and it has an implementor that requires that whatever is passed to it implement the Iterator trait. But I thought I had that covered, because vec.into_iter returns an IntoIter, a consuming iterator which does implement the Iterator trait.
So I'm completely lost as to what's going wrong here. Surely there must be a way to visit a Vec<Result<Value, Error>> as a seq?
Preface: The question wants to treat a Rust data structure Vec<MyData> like a serialized piece of data (e.g.: like a JSON string) and allow deserializing that into any other Rust data structure that implements Deserialize. This is a quite unusual, but not without precedent. And since the MyVals are actually pieces of data with various types which get returned from a database access crate, this approach does make sense.
The main problem with the code in the question is that it tries to deserialize two different data structures (MyWrapper<Vec<MyVal>> and MyVal) with a single Deserializer. The obvious way out is to define a second struct MyValWrapper(MyVal) and implement Deserializer for it:
struct MyValWrapper(MyVal);
impl<'de> Deserializer<'de> for MyValWrapper {
type Error = de::value::Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self.0 {
MyVal::Bool(b) => visitor.visit_bool(b),
MyVal::Text(s) => visitor.visit_string(s.clone()),
}
}
// Maybe you should call deserialize_any from all other deserialize_* functions to get a passable error message, e.g.:
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
// Though maybe you want to handle deserialize_enum differently...
}
MyValWrapper now can deserialize a MyVal. To use MyValWrapper to deserialize a Vec of MyVals, the serde::value::SeqDeserializer adapter is convenient, it can turn an iterator of (Into)Deserializer into a sequence Deserializer:
let data: Vec<MyData> = …;
// Vec deserialization snippet
let mut sd = SeqDeserializer::new(data.into_iter().map(|myval| MyValWrapper(myval)));
let res = visitor.visit_seq(&mut sd)?;
sd.end()?;
Ok(res)
For some reason, SeqDeserializer requires the iterator items to be IntoDeserializer, but no impl<T: IntoDeserializer> Deserializer for T exists, so we need to make sure that MyValWrapper is not only a Deserializer but trivially also an IntoDeserializer:
impl<'de> IntoDeserializer<'de> for MyValWrapper {
type Deserializer = MyValWrapper;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
Finally, you need to impl Deserializer for MyWrapper (you can use the "Vec deserialization snippet" for that) — if you do actually need Deserializer to be implemented, which I suspect you don't: the SeqDeserializer already implements Deserializer, and it is a wrapper struct (just as MyWrapper is a wrapper struct). Especially, if your final goal is having a function like
fn turn_bad_myvals_into_good_T<T: DeserializeOwned>(v: Vec<MyVal>) -> T {
T::deserialize(SeqDeserializer::new(
v.into_iter().map(|myval| MyValWrapper(myval)),
))
}
then you entirely don't need MyWrapper.

Is it possible to cast a trait object to another trait object? [duplicate]

This question already has answers here:
Why doesn't Rust support trait object upcasting?
(5 answers)
Closed 2 years ago.
I tried the following code:
trait TraitA {
fn say_hello(&self) {
self.say_hello_from_a();
}
fn say_hello_from_a(&self);
}
trait TraitB {
fn say_hello(&self) {
self.say_hello_from_b();
}
fn say_hello_from_b(&self);
}
struct MyType {}
impl TraitA for MyType {
fn say_hello_from_a(&self) {
println!("Hello from A");
}
}
impl TraitB for MyType {
fn say_hello_from_b(&self) {
println!("Hello from B");
}
}
fn main() {
let a: Box<dyn TraitA> = Box::new(MyType {});
let b: Box<dyn TraitB>;
a.say_hello();
b = a;
b.say_hello();
}
I get the following compilation error:
error[E0308]: mismatched types
--> src/main.rs:34:9
|
34 | b = a;
| ^ expected trait `TraitB`, found trait `TraitA`
|
= note: expected struct `std::boxed::Box<dyn TraitB>`
found struct `std::boxed::Box<dyn TraitA>`
I declared two traits and a type called MyType and implemented both traits for MyType. I created a new trait object TraitA of type MyType which I called a. Since a also implements TraitB, I thought it should be able to be casted as TraitB.
I haven't figured out if it's even possible. If it is, how can I cast trait object a into TraitB?
In C++, I would use something similar to std::dynamic_pointer_cast<TraitB>(a); for the same purpose.
Here's an example of a case where I could use lateral casting: I have a struct with some data inside that represents some real life entity:
struct MyType {
a: i32,
b: i32,
}
Instances of this type can be used in at least two different parts of the code base. On both parts I need a behavior called get_final_value.
The interesting part is that get_final_value should respond differently depending on who called it.
Why don't I split the type into two different ones?: Technically, by design, a and b belong together, not to say that get_final_value() uses both values to compute the result.
Why not use generics/static dispatch? Because MyType is just one example. In the real case I have different structs, all of them implementing both traits in different ways.
Why not use Any trait? To be honest, I didn't know of it's existence until recently. I don't recall The Rust Programming Language mentioning it. Anyway, it seems you need to know the concrete type to do a cast from Any to that concrete type and then to the trait object.
Another option is to create a trait that uses both TraitA and TraitB as supertraits and provides a cast to each type:
trait TraitC: TraitA + TraitB {
fn as_trait_a(&self) -> &dyn TraitA;
fn as_trait_b(&self) -> &dyn TraitB;
}
Then have MyType implement it:
impl TraitC for MyType {
fn as_trait_a(&self) -> &dyn TraitA {
self
}
fn as_trait_b(&self) -> &dyn TraitB {
self
}
}
Once you do that, you can use TraitC for your Box and your program logic that uses both TraitA and TraitB together.
Sample main to show various ways to use:
fn test_a(a: &TraitA) {
a.say_hello();
}
fn test_b(b: &TraitB) {
b.say_hello();
}
fn main() {
let c: Box<dyn TraitC> = Box::new(MyType {});
TraitA::say_hello(&*c);
TraitB::say_hello(&*c);
c.as_trait_a().say_hello();
c.as_trait_b().say_hello();
test_a(c.as_trait_a());
test_b(c.as_trait_b());
let a: &dyn TraitA = c.as_trait_a();
a.say_hello();
let b: &dyn TraitB = c.as_trait_b();
b.say_hello();
}
Rust Playground
If A and B do truly belong together, this better represents that and still gives you the freedom to use them separately if you desire.
Using Box<MyType> instead of Box<dyn Trait> solves this problem.
fn main() {
let a = Box::new(MyType {});
TraitA::say_hello(&*a);
TraitB::say_hello(&*a);
}
In this case there's no need to use trait objects. Rust has a different paradigm from C++. In most cases you can usually use generic types to solve problems.
If your problem is really suitable to solve with trait objects, you can refer to the OOP chapter in the book.

How can I return an iterator over a slice?

fn main() {
let vec: Vec<_> = (0..5).map(|n| n.to_string()).collect();
for item in get_iterator(&vec) {
println!("{}", item);
}
}
fn get_iterator(s: &[String]) -> Box<Iterator<Item=String>> {
Box::new(s.iter())
}
fn get_iterator<'a>(s: &'a [String]) -> Box<Iterator<Item=&'a String> + 'a> {
Box::new(s.iter())
}
The trick here is that we start with a slice of items and that slice has the lifetime 'a. slice::iter returns a slice::Iter with the same lifetime as the slice. The implementation of Iterator likewise returns references with that lifetime. We need to connect all of the lifetimes together.
That explains the 'a in the arguments and in the Item=&'a part. So what's the + 'a mean? There's a complete answer about that, and another with more detail. The short version is that an object with references inside of it may implement a trait, so we need to account for those lifetimes when talking about a trait. By default, that lifetime is 'static as it was determined that was the usual case.
The Box is not strictly required, but is a normal thing you'll see when you don't want to deal with the complicated types that might underlie the implementation (or just don't want to expose the implementation). In this case, the function could be
fn get_iterator<'a>(s: &'a [String]) -> std::slice::Iter<'a, String> {
s.iter()
}
But if you add .skip(1), the type would be:
std::iter::Skip<std::slice::Iter<'a, String>>
And if you involve a closure, then it's currently impossible to specify the type, as closures are unique, anonymous, auto-generated types! A Box is required for those cases.

Working around the limitations of extension traits

The pattern of having an object-safe trait Foo and a (potentially unsafe) extension trait FooExt implemented for all instances of Foo seems to become standard now.
https://github.com/rust-lang/rfcs/pull/445
This is a problem for me in the case of Iterator<A>, as I have a library that overrides the default method IteratorExt#last() of the old iterator trait (the underlying library has an efficient implementation of last()). This in now impossible, because for any A, there will always be a conflicting trait implementation of IteratorExt, the one that libcore already provides for all Iterator<A>.
iterator.rs:301:1: 306:2 error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]
iterator.rs:301 impl<'a, K: Key> iter::IteratorExt<Vec<u8>> for ValueIterator<'a,K,Vec<u8>> {
iterator.rs:302 fn last(&mut self) -> Option<Vec<u8>> {
iterator.rs:303 self.seek_last();
iterator.rs:304 Some(self.value())
iterator.rs:305 }
iterator.rs:306 }
...
Now, as far as I see, I have two options:
have my own trait and my own last() implementation. That would mean it conflicts if IteratorExt is imported unless carefully used. This also has the danger accidentally using an inefficient version of last() if the version from IteratorExt is used. I'd loose convenient access to IteratorExt.
have my own trait and name the method differently (seek_last()). Disadvantage: I ask the user to learn vocabulary and to always favor my method over that provided by IteratorExt. Same problem: I'd like to avoid accidental usage of last().
Is there any other, better, solution I am missing?
As of rustc 0.13.0-nightly (8bca470c5 2014-12-08 00:12:30 +0000) defining last() as an inherent method on your type should work.
#[deriving(Copy)]
struct Foo<T> {t: T}
impl<T> Iterator<T> for Foo<T> {
fn next(&mut self) -> Option<T> { None }
}
// this does not work
// error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]
// impl<T> IteratorExt<T> for Foo<T> {
// fn last(mut self) -> Option<T> { None }
//}
// but this currently does
impl<T> Foo<T> {
fn last(mut self) -> Option<T> { Some(self.t) }
}
fn main() {
let mut t = Foo{ t: 3u };
println!("{}", t.next())
println!("{}", t.last()) // last has been "shadowed" by our impl
println!("{}", t.nth(3)) // other IteratorExt methods are still available
}
Since you're not supposed to use Extension traits as generic bounds (but just to provide additional methods), this should theoretically work for your scenario, as you can have your own type and its impl in the same crate.
Users of your type will use the inherent last method instead of the one on IteratorExt but still be able to use the other methods on IteratorExt.
last should be moved to Iterator, rather than IteratorExt.
IteratorExt is needed when using Box<Iterator> objects, to allow calling generic methods on them (e.g. map), because you can't put a generic method in a vtable. However, last isn't generic, so it can be put in Iterator.