Can I have a static borrowed reference to a trait object? - traits

Is there a way for me to obtain a static borrowed reference to a struct's implementation of a trait:
trait Trait {}
struct Example;
impl Trait for Example {}
This works fine:
static instance1: Example = Example;
This also works fine:
static instance2: &'static Example = &Example;
But this doesn't work:
static instance3: &'static Trait = &Example as &'static Trait;
It fails thus:
error[E0277]: the trait bound `Trait + 'static: std::marker::Sync` is not satisfied in `&'static Trait + 'static`
--> src/main.rs:10:1
|
10 | static instance3: &'static Trait = &Example as &'static Trait;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait + 'static` cannot be shared between threads safely
|
= help: within `&'static Trait + 'static`, the trait `std::marker::Sync` is not implemented for `Trait + 'static`
= note: required because it appears within the type `&'static Trait + 'static`
= note: shared static variables must have a type that implements `Sync`
Alternatively, is there a way to obtain a borrowed static pointer to a trait from a global borrowed static pointer to a struct:
static instance2: &'static Example = &Example;
fn f(i: &'static Trait) {
/* ... */
}
fn main() {
// how do I invoke f passing in instance2?
}

Yes, you can, if the trait also implements Sync:
trait Trait: Sync {}
struct Example;
impl Trait for Example {}
static INSTANCE3: &dyn Trait = &Example;
Or if you declare that your trait object also implements Sync:
trait Trait {}
struct Example;
impl Trait for Example {}
static INSTANCE3: &(dyn Trait + Sync) = &Example;
Types that implement Sync are those
[...] for which it is safe to share references between threads.
This trait is automatically implemented when the compiler determines it's appropriate.
The precise definition is: a type T is Sync if &T is Send. In other words, if there is no possibility of undefined behavior (including data races) when passing &T references between threads.
Since you are sharing a reference, any thread would be able to call methods on that reference, so you need to ensure that nothing would violate Rust's rules if that happens.

Related

Rust define trait interface for any type?

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

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.

I can't have every trait and impl in the same file; how to place in seperate file?

I have a struct, a trait, and impl in the top level file.
struct Model {}
trait TsProperties {
fn create_ar_x_matrix(&self);
}
impl TsProperties for Model {
fn create_ar_x_matrix(&self){}
}
I want to move the trait and impl to a separate file called test.rs. In the main file I have:
mod test
In test I have:
use crate::Model;
When I instantiate the struct, Intellisense does not pick up create_ar_x_matrix. If the code is in main.rs it does.
How do I resolve this?
If I add pub I get this error:
25 | pub impl TsProperties for Model {
| ^^^ `pub` not permitted here because it's implied
if I use pub on the struct in main file and put the trait in a separate file:
error[E0599]: no method named `create_ar_x_matrix` found for type `Model` in the current scope
--> src/main.rs:353:12
|
64 | pub struct Model {
| --------------------- method `create_ar_x_matrix` not found for this
You need to import the trait.
In test.rs:
use crate::Model;
pub trait TsProperties {
fn create_ar_x_matrix(&self);
}
impl TsProperties for Model {
fn create_ar_x_matrix(&self){}
}
In main.rs:
mod test;
use self::test::TsProperties;
struct Model {}
fn main() {
let model = Model {};
model.create_ar_x_matrix();
}
Note that Model doesn't need to be public, but the trait does. That's because anything in a parent module is automatically visible in child modules.

Constrain parent trait to reference

I want to define a trait Container such that every implementor of this trait also needs to implement IntoIterator, with the caveat that the iteration ALWAYS only borrows the instance. If I understand correctly, I can implement IntoIterator using a pattern like this:
impl<'a> IntoIterator for &'a ContainerImpl
However, how can I specify that this needs to be implemented if a type implements Container, e.g.:
trait Container: &IntoIter ???
You can add a where clause to traits, too (playground):
trait IterBorrow where for<'a> &'a Self: IntoIterator {}
impl IterBorrow for [i32] {} // legal
// impl IterBorrow for i32 {} // Illegal
However, it seems you currently need to reiterate this bound whenever you actually want to iterate, i.e., this function does not compile without the where clause:
fn foo<T: IterBorrow>(x: T) where for<'a> &'a T: IntoIterator {
for _ in &x {}
for _ in &x {}
}

Rust struct can borrow "&'a mut self" twice, so why can't a trait?

The following Rust code compiles successfully:
struct StructNothing;
impl<'a> StructNothing {
fn nothing(&'a mut self) -> () {}
fn twice_nothing(&'a mut self) -> () {
self.nothing();
self.nothing();
}
}
However, if we try to package it in a trait, it fails:
pub trait TraitNothing<'a> {
fn nothing(&'a mut self) -> () {}
fn twice_nothing(&'a mut self) -> () {
self.nothing();
self.nothing();
}
}
This gives us:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:6:9
|
1 | pub trait TraitNothing<'a> {
| -- lifetime `'a` defined here
...
5 | self.nothing();
| --------------
| |
| first mutable borrow occurs here
| argument requires that `*self` is borrowed for `'a`
6 | self.nothing();
| ^^^^ second mutable borrow occurs here
Why is the first version allowed, but the second version forbidden?
Is there any way to convince the compiler that the second version is OK?
Background and motivation
Libraries like rust-csv would like to support streaming, zero-copy parsing because it's 25 to 50 times faster than allocating memory (according to benchmarks). But Rust's built-in Iterator trait can't be used for this, because there's no way to implement collect(). The goal is to define a StreamingIterator trait which can be shared by rust-csv and several similar libraries, but every attempt to implement it so far has run into the problem above.
The following is an extension of Francis's answer using implicit lifetimes but it allows for the return value to be lifetime bound:
pub trait TraitNothing<'a> {
fn change_it(&mut self);
fn nothing(&mut self) -> &Self {
self.change_it();
self
}
fn bounded_nothing(&'a mut self) -> &'a Self {
self.nothing()
}
fn twice_nothing(&'a mut self) -> &'a Self {
// uncomment to show old fail
// self.bounded_nothing();
// self.bounded_nothing()
self.nothing();
self.nothing()
}
}
It's less than perfect, but you can call the methods with implicit lifetimes change_it and nothing multiple times within other methods. I don't know if this will solve your real problem because ultimately self has the generic type &mut Self in the trait methods whereas in the struct it has type &mut StructNothing and the compiler can't guarantee that Self doesn't contain a reference. This workaround does solve the code example.
If you put the lifetime parameters on each method rather than on the trait itself, it compiles:
pub trait TraitNothing {
fn nothing<'a>(&'a mut self) -> () {}
fn twice_nothing<'a>(&'a mut self) -> () {
self.nothing();
self.nothing();
}
}
Nobody seemed to answer the "why?" so here I am.
Here's the point: In the trait, we're calling methods from the same trait. However, in the free impl, we're not calling methods from the same impl.
What? Surely we call methods from the same impl?
Let's be more precise: we're calling methods from the same impl, but not with the same generic parameters.
Your free impl is essentially equivalent to the following:
impl StructNothing {
fn nothing<'a>(&'a mut self) {}
fn twice_nothing<'a>(&'a mut self) {
self.nothing();
self.nothing();
}
}
Because the impl's generic lifetime is floating, it can be chosen separately for each method. The compiler does not call <Self<'a>>::nothing(self), but rather it calls <Self<'some_shorter_lifetime>>::nothing(&mut *self).
With the trait, on the other hand, the situation is completely different. The only thing we can know for sure is that Self: Trait<'b>. We cannot call nothing() with a shorter lifetime, because maybe Self doesn't implement Trait with the shorter lifetime. Therefore, we are forced to call <Self as Trait<'a>>::nothing(self), and the result is that we're borrowing for overlapping regions.
From this we can infer that if we tell the compiler that Self implements Trait for any lifetime it will work:
fn twice_nothing(&'a mut self)
where
Self: for<'b> TraitNothing<'b>,
{
(&mut *self).nothing();
(&mut *self).nothing();
}
...except it fails to compile because of issue #84435, so I don't know whether this would have succeeded :(
Is this really surprising?
The assertion you're making is that &mut self lasts for at least the lifetime 'a.
In the former case, &mut self is a pointer to a struct. No pointer aliasing occurs because the borrow is entirely contained in nothing().
In the latter case, the &mut self is a pointer to a pointer to a struct + a vtable for the trait. You're locking the pointed to struct that implements TraitNothing for the duration of 'a; i.e. the whole function each time.
By removing 'a, you're implicitly using 'static, which says the impl lasts forever, so its fine.
If you want to work around it, transmute the &'a TraitNothing to &'static TraitNothing... but I'm pretty sure that's not what you want to do.
This is why we need block scopes ('b: { .... }) in Rust...
Try using dummy lifetimes perhaps?