Turn an upstream struct into a trait - rust

I've got to interact with some upstream code that exposes an interface that could be a trait but is instead implemented directly on a struct. I'd like to pull out that interface into a trait so that my code can support alternative implementations. This can in fact be done, but isn't particularly ergonomic:
pub mod upstream_code {
pub struct Foo(());
impl Foo {
pub fn foo(&self) -> &'static str {
"foo"
}
}
impl Default for Foo {
fn default() -> Self {
Foo(())
}
}
}
mod my_code {
pub trait Foo {
fn foo(&self) -> &'static str;
}
impl Foo for super::upstream_code::Foo {
fn foo(&self) -> &'static str {
self.foo()
}
}
pub fn do_something<T: Foo>(t: T) {
println!("foo: {}", t.foo());
}
}
fn main() {
my_code::do_something(upstream_code::Foo::default());
}
Specifically, note that I have to regurgitate each function in wrapper form inside the impl Foo for super::upstream_code::Foo block.
There's Got To Be A Better Way! What's the most idiomatic way of handling this?

Related

How to create new objects of any type that is passed as an argument to a function in Rust

I need to be able to create new objects from any struct that implements some trait, is there a way to achieve that? Right now create_obj accepts objects of struct that implements trait, but in my program I don't have struct objects, they are implemented by user of a library.
trait Tr: {
fn new() -> Self;
}
struct St {}
impl Tr for St {
fn new() -> Self {
Self
}
}
// I want this function to be able to create any objects (that impl Tr) for me
fn create_obj<T: Tr>(t: T) -> Box<dyn Tr> {
Box::new(T::new())
}
#[cfg(test)]
mod tests {
use crate::{create_obj, St};
#[test]
fn it_works() {
// Here I want to pass a struct type that implements the trait, not the struct object
create_obj(St);
}
}
Above code obviously fails with:
^^ help: use struct literal syntax instead: `St {}`
For anyone struggling, here's how I did it:
trait Tr: {
fn new() -> Self;
}
struct St {}
impl Tr for St {
fn new() -> Self {
St {}
}
}
fn create_obj<U>() -> U
where
U: Tr
{
let state = U::new();
state
}
#[cfg(test)]
mod tests {
use crate::{create_obj, St};
#[test]
fn it_works() {
create_obj::<St>();
}
}

Allowing extension (beyond the crate) of implementation with event loop

Within the crate we can happily do something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
}
use boundary::EventLoopExtend;
impl EventLoopExtend for boundary::EventLoop {
fn foo(&self) {
self.handle("extended")
}
}
fn main() {
let el = boundary::EventLoop{};
el.run();
}
But if mod boundary were a crate boundary we get error[E0117]: only traits defined in the current crate can be implemented for arbitrary types.
I gather that a potential solution to this could be the New Type idiom, so something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
impl EventLoopExtend for EventLoop {
fn foo(&self) {
self.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopNewType(EventLoop);
impl EventLoopExtend for EventLoopNewType {
fn foo(&self) {
self.0.handle("extended")
}
}
fn main() {
let el = EventLoopNewType(EventLoop {});
el.0.run();
}
But then the problem here is that the extended trait behaviour isn't accessible from the underlying EventLoop instance.
I'm still quite new to Rust, so I'm sure I'm missing something obvious, I wouldn't be surprised if I need to take a completely different approach.
Specifically in my case, the event loop is actually from wgpu, and I'm curious if it's possible to build a library where end users can provide their own "render pass" stage.
Thanks to #AlexN's comment I dug deeper into the Strategy Pattern and found a solution:
mod boundary {
pub struct EventLoop<'a, T: EventLoopExtend> {
extension: &'a T
}
impl<'a, T: EventLoopExtend> EventLoop<'a, T> {
pub fn new(extension: &'a T) -> Self {
Self { extension }
}
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.extension.foo(self);
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopExtension;
impl EventLoopExtend for EventLoopExtension {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("extended")
}
}
fn main() {
let el = EventLoop::new(&EventLoopExtension {});
el.run();
}
The basic idea is to use generics with a trait bound. I think the first time I looked into this approach I was worried about type recursion. But it turns out passing the EventLoop object as an argument to EventLoopExtend trait methods is perfectly reasonable.

How to avoid orphan rules for repr transparent wrappers

My problem is I want to have a transparent wrapper and implemented Into<underlying> for it. Unfortunately, rust's orphan rules forbid it. Here is a simple example:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> Into<T> for MyWrapper<T> {
fn into(self) -> T {
self.0
}
}
The question is is there any way I can implement it? I'm using macro to generate impl for all types I'm currently using but it looks very awkward and dirty.
You can implement the Deref trait instead. The Deref docs contain the following example which is almost identical to your code:
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
You can implement it in a regular impl block:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> MyWrapper<T> {
pub fn into(self) -> T {
self.0
}
}
fn main() {
let wrapped : MyWrapper<f32> = MyWrapper::<f32>(3.4f32);
let unwrapped : f32 = wrapped.into();
println!("{}", unwrapped);
}

Implementing Rust traits cause struct to not be found

When I implement a trait on a struct in Rust it's causing the struct type not to be found. First, the working code:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeStruct {
fn new() -> Box<SomeStruct> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
Here the SomeTrait trait isn't being used. Everything works. If I now change the impl of SomeStruct to implement SomeTrait:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeTrait for SomeStruct {
fn new() -> Box<SomeTrait> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
I get the error:
trait.rs:21:13: 21:28 error: failed to resolve. Use of undeclared module `SomeStruct`
trait.rs:21 let obj = SomeStruct::new();
^~~~~~~~~~~~~~~
trait.rs:21:13: 21:28 error: unresolved name `SomeStruct::new`.
trait.rs:21 let obj = SomeStruct::new();
What am I doing wrong? Why is SomeStruct suddenly missing? Thanks!
At the moment, associated functions (non-method functions) in traits are called via the trait, i.e. SomeTrait::new(). However, if you just write this, the compiler cannot work out which impl you're using, as there's no way to specify the SomeStruct information (it only works if the special Self type is mentioned in the signature somewhere). That is, the compiler needs to be able to work out which version of new should be called. (And this is required; they could have very different behaviour:
struct Foo;
impl SomeTrait for Foo {
fn new() -> Box<SomeTrait> { box Foo as Box<SomeTrait> }
}
struct Bar;
impl SomeTrait for Bar {
fn new() -> Box<SomeTrait> {
println!("hello")
box Bar as Box<SomeTrait>
}
}
Or something more dramatic than just printing.)
This is a language hole that will be filled by UFCS. For the moment, you need to use the dummy-Self trick:
trait SomeTrait {
fn new(_dummy: Option<Self>) -> Box<SomeTrait>;
...
}
which is then called like SomeTrait::new(None::<SomeStruct>).
However, I question why you are returning a boxed object from a constructor. This is rarely a good idea, it's normally better to just return the plain type directly, and the user can box it if necessary, that is,
trait SomeTrait {
fn new() -> Self;
...
}
(NB. this signature mentions Self and thus the Option trick above isn't required.)
Sidenote: the error message is rather bad, but it just reflects how these methods are implemented; an associated function in an impl Foo is very similar to writing mod Foo { fn ... }. You can see it differ by forcing the compiler to create that module:
struct Foo;
impl Foo {
fn bar() {}
}
fn main() {
Foo::baz();
}
prints just
<anon>:7:5: 7:13 error: unresolved name `Foo::baz`.
<anon>:7 Foo::baz();
^~~~~~~~
i.e. the Foo "module" exists.

How to call a trait method without a struct instance?

If I have a struct with a method that doesn't have self as an argument, I can call the method via SomeStruct::method(). I can't seem to do the same with a method that's defined from a trait. For example:
trait SomeTrait {
fn one_trait() -> uint;
}
struct SomeStruct;
impl SomeStruct {
fn one_notrait() -> uint {
1u
}
}
impl SomeTrait for SomeStruct {
fn one_trait() -> uint {
1u
}
}
#[test]
fn testing() {
SomeStruct::one_trait(); // doesn't compile
SomeStruct::one_notrait(); // compiles
}
The compiler gives the error "unresolved name 'SomeStruct::one_trait.'"
How can I call a struct's implementation of a trait method directly?
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
fn main() {
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}
From Advanced Trait
I believe this is currently not possible. The problem is that you cannot explicitly specify the Self type. But there is an active RFC in the pipeline which should allow this when implemented.
In the meantime, you could work around it like this:
trait SomeTrait {
fn one_trait(&self) -> uint;
}
struct Static<T>;
struct SomeStruct;
impl SomeTrait for Static<SomeStruct> {
fn one_trait(&self) -> uint { 1 }
}
fn main() {
let type_to_uint = Static::<SomeStruct>.one_trait();
println!("{}", type_to_uint);
}
This is how I map a type to an integer (if that's what you're after). It's done without having a value of type T. The dummy value, Static<T>, has a size of zero.

Resources