Digging into the subject of the orphan rule, I ended up with a kind of implementation of a trait by a type both defined outside the implementing crate. But as a result, I now have another question about trait implementation. The following example works well:
orphan/ | c1/ | src/lib.rs | pub trait MyTrait<T> {
| | | fn my_task(&self);
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c2/ | src/lib.rs | pub struct MyStruct;
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c3/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
| | | pub enum MyT {}
| | | impl MyTrait<MyT> for MyStruct {
| | | fn my_task(&self) { println!("This is c3 implementation"); }
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c4/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
| | | pub enum MyT {}
| | | impl MyTrait<MyT> for MyStruct {
| | | fn my_task(&self) { println!("This is c4 implementation"); }
| | | }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| c5/ | src/main.rs | mod _3 {
| | | use c1::*; use c2::*; use c3::*;
| | | pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| | | }
| | | mod _4 {
| | | use c1::*; use c2::*; use c4::*;
| | | pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| | | }
| | | fn main() { _3::f(); _4::f(); }
| |
| | Cargo.toml -> DEFINITION BELOW
|
| Cargo.toml | [workspace]
| members = [ "c1", "c2", "c3", "c4", "c5", ]
with result:
cargo run --release
Compiling c5 v0.0.1 (XXX\orphan\c5)
Finished release [optimized] target(s) in 0.27s
Running `target\release\c5.exe`
This is c3 implementation
This is c4 implementation
But if I replace the main by:
main.rs | mod _3 {
| use c1::*; use c2::*; use c3::*;
| pub fn f() { MyTrait::my_task(&MyStruct); }
| }
| mod _4 {
| use c1::*; use c2::*; use c4::*;
| pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
| }
| fn main() { _3::f(); _4::f(); }
the following error is obtained:
--> c5\src\main.rs:3:18
|
3 | pub fn f() { MyTrait::my_task(&MyStruct); }
| ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the trait `MyTrait`
|
= note: multiple `impl`s satisfying `c2::MyStruct: c1::MyTrait<_>` found in the following crates: `c3`, `c4`:
- impl c1::MyTrait<c3::MyT> for c2::MyStruct;
- impl c1::MyTrait<c4::MyT> for c2::MyStruct;
Why such error, while "use c3::...;" and "use c4::...;" are applied within separated mods?
By the way, the following case works perfectly (unused_imports allowed only to avoid warnings):
main.rs | mod _3 {
| use c1::*; use c2::*; #[allow(unused_imports)] use c3::*;
| pub fn f() { MyTrait::my_task(&MyStruct); }
| }
| fn main() { _3::f(); }
with result:
cargo run --release
Compiling c5 v0.0.1 (XXX\orphan\c5)
Finished release [optimized] target(s) in 0.28s
Running `target\release\c5.exe`
This is c3 implementation
This behavior is thus a little bit strange : the compiler desagrees with the absence of turbofish only when both c3::MyT and c4::MyT are used, but that seems unlogic because they are used in separated mods.
ADD-ON: Detailed definition of the cargo files:
c1/Cargo.toml | [package]
| name = "c1"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
c2/Cargo.toml | [package]
| name = "c2"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
c3/Cargo.toml | [package]
| name = "c3"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
c4/Cargo.toml | [package]
| name = "c4"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
c5/Cargo.toml | [package]
| name = "c5"
| version = "0.0.1"
| edition = "2021"
| [dependencies]
| c1 = { path = "../c1", version = "0.0.1" }
| c2 = { path = "../c2", version = "0.0.1" }
| c3 = { path = "../c3", version = "0.0.1" }
| c4 = { path = "../c4", version = "0.0.1" }
It is because your trait is generic, and there is no real way for Rust to figure out which type it should be without the turbofish (::<>). In this case, it seems obvious because there is only one impl, but that's not typical, because then there isn't really a point of it being generic.
To see this yourself, in c3, you can add a second impl block, and now it is pretty easy to see what it means by cannot infer type parameter T, it could just as easily be MyT or i32.
impl MyTrait<MyT> for MyStruct {
fn my_task(&self) { println!("This is c3 implementation"); }
}
impl MyTrait<i32> for MyStruct {
fn my_task(&self) { println!("This is c3 implementation for i32"); }
}
You can then specify either type in _3::f to disambiguate the function call:
MyTrait::<MyT>::my_task(&MyStruct);
MyTrait::<i32>::my_task(&MyStruct);
I don't have a good explanation on why your last example ("the following case works perfectly") doesn't experience the same issues though.
Implementations seem ubiquitous through the entire crate as shown in example: [playground]
trait Trait {
fn my_fn();
}
enum Enum {}
mod _nothing_mod {
struct _Nothing;
impl _Nothing {
fn _do_nothing() {
use crate::{ Enum, Trait, };
impl Trait for Enum {
fn my_fn() {
impl Enum {
pub fn new() -> Option<Self> {
println!("cannot create Enum instance");
None
}
}
println!("a task")
}
}
}
}
}
fn main() {
Enum::new();
Enum::my_fn();
}
resulting in:
Standard Error
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/playground`
Standard Output
cannot create Enum instance
a task
For this reason, it is not possible in the example of this question to use the two implementations of MyTrait for MyStruct in same crate c5 without using the turbofish.
Related
In the following code using gtk-rs I continuously get the error "method cannot be called on gtk4::Box due to unsatisfied trait bounds" for "hbox.pack_start". I have seen this method working in other gtk-rs applications and in the documentation, so I'm not sure what I am doing wrong.
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Button, Label};
fn main() {
let app = Application::builder()
.application_id("org.kresslein.rkcounter")
.build();
app.connect_activate(build_ui);
app.run();
}
fn build_ui(app: &Application) {
let hbox: gtk::Box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
hbox.set_homogeneous(false);
let app_title = Label::new(Some("Counter"));
// Problematic line:
hbox.pack_start(&app_title, true, true, 0);
let window = ApplicationWindow::builder()
.application(app)
.title("Counter")
.child(&hbox)
.build();
// Present window
window.present();
}
Here is the full error message:
error[E0599]: the method `pack_start` exists for struct `gtk4::Box`, but its trait bounds were not satisfied
--> src/main.rs:47:10
|
47 | hbox.pack_start(&app_title);
| ^^^^^^^^^^ method cannot be called on `gtk4::Box` due to unsatisfied trait bounds
|
::: /home/ricky/.cargo/registry/src/github.com-1ecc6299db9ec823/gtk4-0.3.1/src/auto/box_.rs:27:1
|
27 | / glib::wrapper! {
28 | | #[doc(alias = "GtkBox")]
29 | | pub struct Box(Object<ffi::GtkBox, ffi::GtkBoxClass>) #extends Widget, #implements Accessible, Buildable, ConstraintTarget, Orientable;
30 | |
... |
33 | | }
34 | | }
| | -
| | |
| |_doesn't satisfy `gtk4::Box: IsA<CellLayout>`
| doesn't satisfy `gtk4::Box: gtk4::prelude::CellLayoutExt`
|
= note: the following trait bounds were not satisfied:
`gtk4::Box: IsA<CellLayout>`
which is required by `gtk4::Box: gtk4::prelude::CellLayoutExt`
For more information about this error, try `rustc --explain E0599`.
I am having problem getting a reference out of a RefCell<Option<Rc>>.
Any suggestion?
struct Node<T> {
value: T
}
struct Consumer3<T> {
tail: RefCell<Option<Rc<Node<T>>>>,
}
impl<T> Consumer3<T> {
fn read<'s>(&'s self) -> Ref<Option<T>> {
Ref::map(self.tail.borrow(), |f| {
f.map(|s| {
let v = s.as_ref();
v.value
})
})
}
}
Gives:
error[E0308]: mismatched types
--> src/lib.rs:15:13
|
15 | / f.map(|s| {
16 | | let v = s.as_ref();
17 | | v.value
18 | | })
| |______________^ expected reference, found enum `Option`
|
= note: expected reference `&_`
found enum `Option<T>`
help: consider borrowing here
|
15 | &f.map(|s| {
16 | let v = s.as_ref();
17 | v.value
18 | })
|
error: aborting due to previous error
Playground
Mapping from one Ref to another requires that the target already exist in memory somewhere. So you can't get a Ref<Option<T>> from a RefCell<Option<Rc<Node<T>>>>, because there's no Option<T> anywhere in memory.
However, if the Option is Some, then there will be a T in memory from which you can obtain a Ref<T>; if the Option is None, obviously you can't. So returning Option<Ref<T>> may be a viable alternative for you:
use std::{cell::{Ref, RefCell}, rc::Rc};
struct Node<T> {
value: T
}
struct Consumer3<T> {
tail: RefCell<Option<Rc<Node<T>>>>,
}
impl<T> Consumer3<T> {
fn read(&self) -> Option<Ref<T>> {
let tail = self.tail.borrow();
if tail.is_some() {
Some(Ref::map(tail, |tail| {
let node = tail.as_deref().unwrap();
&node.value
}))
} else {
None
}
}
}
Playground.
I'm trying to implement the builder pattern from the proc macro workshop I'm creating a proc macro which parses a struct, extracts its name, field_names and field_types. It should reproduce the struct itself and also create a builder struct with the same field_names but with optional types.
My problem is that field_name and field_type are iterators that I would have to use twice in order to create two structs out of one.
This is my source tree
.
├── Cargo.lock
├── Cargo.toml
├── builder-derive
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── src
└── main.rs
./cargo.toml
[package]
name = "proc-macro-question"
version = "0.1.0"
authors = ["ropottnik <ropottnik#example.com>"]
edition = "2018"
[dependencies]
builder-derive = { path = "./builder-derive" }
./main.rs
#[derive(Builder)]
struct SomeStruct {
some_field: i32,
}
fn main() {
println!("Hello, world!");
}
./builder-derive/cargo.toml
[package]
name = "builder-derive"
version = "0.1.0"
authors = ["ropottnik <ropottnik#example.com>"]
edition = "2018"
[lib]
proc-macro = true
[dev-dependencies]
trybuild = { version = "1.0", features = ["diff"] }
[dependencies]
syn = { version= "1.0", features = ["extra-traits"] }
quote = "1.0"
./builder-derive/src/lib.rs
#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let builder_name = format_ident!("{}Builder", &name);
let fields = match &input.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
let field_name = fields.iter().map(|field| &field.ident);
let field_type = fields.iter().map(|field| &field.ty);
let expanded = quote! {
pub struct #name {
#(#field_name: #field_type,)*
}
pub struct #builder_name {
#(#field_name: Option<#field_type>,)*
}
};
expanded.into()
}
$ cargo run output
warning: unused import: `Ident`
--> builder-derive/src/lib.rs:1:18
|
1 | use proc_macro::{Ident, TokenStream};
| ^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0382]: use of moved value: `field_name`
--> builder-derive/src/lib.rs:22:20
|
19 | let field_name = fields.iter().map(|field| &field.ident);
| ---------- move occurs because `field_name` has type `Map<syn::punctuated::Iter<'_, syn::Field>, [closure#builder-derive/src/lib.rs:19:40: 19:60]>`, which does not implement the `Copy` trait
...
22 | let expanded = quote! {
| ____________________^
23 | | pub struct #name {
24 | | #(#field_name: #field_type,)*
25 | | }
... |
29 | | }
30 | | };
| | ^
| | |
| |_____`field_name` moved due to this method call
| value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `field_name`
--> /Users/simon/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.8/src/runtime.rs:53:28
|
53 | fn quote_into_iter(self) -> (Self, HasIter) {
| ^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0382]: use of moved value: `field_type`
--> builder-derive/src/lib.rs:22:20
|
20 | let field_type = fields.iter().map(|field| &field.ty);
| ---------- move occurs because `field_type` has type `Map<syn::punctuated::Iter<'_, syn::Field>, [closure#builder-derive/src/lib.rs:20:40: 20:57]>`, which does not implement the `Copy` trait
21 |
22 | let expanded = quote! {
| ____________________^
23 | | pub struct #name {
24 | | #(#field_name: #field_type,)*
25 | | }
... |
29 | | }
30 | | };
| | ^
| | |
| |_____`field_type` moved due to this method call
| value used here after move
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
I guess I could create one iterator per usage but that seems impossibly dumb to me ;-)
Iterators can only be used zero or one time, not multiple; that's standard Rust and doesn't involve the quote! macro:
fn example() {
let nums = std::iter::empty::<i32>();
for _ in nums {}
for _ in nums {}
}
error[E0382]: use of moved value: `nums`
--> src/lib.rs:4:14
|
2 | let nums = std::iter::empty::<i32>();
| ---- move occurs because `nums` has type `std::iter::Empty<i32>`, which does not implement the `Copy` trait
3 | for _ in nums {}
| ----
| |
| `nums` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&nums`
4 | for _ in nums {}
| ^^^^ value used here after move
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `nums`
Even if you took the iterators by mutable reference, iterating through it once would exhaust it, leaving no values for the second usage.
You will need to clone the iterator:
use quote::quote; // 1.0.8
fn example() {
let nums = std::iter::empty::<i32>();
let nums2 = nums.clone();
quote! {
#(#nums)*
#(#nums2)*
};
}
You can also collect the iterator into a Vec and iterate over it multiple times:
use quote::quote; // 1.0.8
fn example() {
let nums = std::iter::empty();
let nums: Vec<i32> = nums.collect();
quote! {
#(#nums)*
#(#nums)*
};
}
I made a simple macro that defines a struct.
macro_rules! __body {
($($body:tt)+) => {
$($body)+
};
}
macro_rules! new_struct {
($(#[$attr:meta])* struct $name:ident { $($body:tt)+ } ) => {
$(#[$attr])* struct $name {
__body!($($body)+);
}
};
}
new_struct! {
#[derive(Deserialize)]
struct Test {
a: bool,
b: String,
}
}
When I compile this code, it raises an error:
|
14 | __body!($($body)+);
| ^ expected `:`
...
19 | / new_struct! {
20 | | #[derive(Deserialize)]
21 | | struct Test {
22 | | a: bool,
23 | | b: String,
24 | | }
25 | | }
| |_- in this macro invocation
|
According to the reference:
Macros can expand to expressions, statements, items (including traits, impls, and foreign items), types, or patterns.
and struct fields are none of these, so you cannot use a declarative macro for that. You may want to try procedural macros instead.
I am attempting to pass a closure to a function after a condition:
extern crate futures;
extern crate tokio_core;
use futures::prelude::*;
use futures::future;
use futures::unsync::*;
use tokio_core::reactor::*;
fn main() {
let mut core = Core::new().unwrap();
let h2 = core.handle();
let fun = |should: Result<bool, ()>| {
if should.unwrap_or(true) {
// do something
}
future::ok(())
};
let (tx, rx) = oneshot::channel::<bool>();
let dummy = true;
if dummy {
h2.spawn(rx.then(fun));
} else {
h2.spawn(future::ok(true).then(fun));
}
core.run(future::ok::<(), ()>(())).unwrap();
}
Here is the code in the playground, but it is getting a different error from the error baffling me. My error looks like:
error[E0593]: closure takes 0 arguments but 1 argument is required
--> src/client/forger.rs:123:25
|
57 | let fun = |should: Result<bool, ()>| {
| ___________________-
58 | | if !should.unwrap_or(false) {
59 | | return Box::new(future::ok::<(), ()>(()));
60 | | }
... |
117 | | Box::new(future::ok(()))
118 | | };
| |_________- takes 0 arguments
...
123 | h2.spawn(rx.then(fun));
| ^^^^ expected closure that takes 1 argument
Why does Rust say the function fun takes 0 arguments when it appears to quote it as taking one?
My Rust version is 1.22.1.
Turns out that my Rust version was 1.22.1, but the latest version is 1.23.0. This explains why the playground was returning a more accurate error: expected signature of fn(std::result::Result<bool, futures::Canceled>) -> _... which was the problem exactly.