I'm trying to define a structure storing values of type FnMut(&E) for some generic type E:
struct Publisher<E,F> where F: FnMut(&E) {
subscribers: Vec<F>
}
However, the Rust compiler then complains that E is never used, while omitting it causes it to fail since E is unknown. While it is possible to get around this using phantom data
struct Publisher<E,F> where F: FnMut(&E) {
subscribers: Vec<F>,
event: core::marker::PhantomData<E>
}
this approach doesn't seem very elegant. What would be the right way to address this issue?
Related
This question already has an answer here:
Any way to get associated type from struct?
(1 answer)
Closed 10 months ago.
So I'm making a little tictactoe to learn Rust. I define a Board which is a struct containing a 3 by 3 array called "tiles".
pub struct Board {
pub tiles: [[Option<Players>; 3]; 3],
}
Then, I try to create a method that uses the element "tiles" as a parameter
impl Board {
pub fn print_board (board: Board::tiles) {
}
However, Rust gets all offended and tells me this.
ambiguous associated typerustcE0223 game.rs(10, 32): use fully-qualified syntax: "<Board as Trait>::tiles"
First of all, I have no idea what this mean, but then I try to do as it says:
impl Board {
pub fn print_board (board: <Board as Trait>::tiles) {
}
it gives me squiggles under "Trait" where it says
failed to resolve: use of undeclared type "Trait" use of undeclared type "Trait"
Rust, o Rust what ever am I supposed to do?
Board::tiles doesn't make syntactic sense. If board is a value of type Board, then board.tiles is a data member of the struct. Neither Board::tiles nor board.tiles is a type so you can't use it for defining the type of an argument.
You can either take the type of the data member explicitly, like this: pub fn print_board(board: [[Option<Players>; 3]; 3]).
Or if you don't want to write out that type again and again you can use a type alias like this
pub type TileArray = [[Option<Players>; 3]; 3];
pub struct Board {
pub tiles: TileArray,
}
impl Board {
pub fn print_board(board: TileArray) {
// ...
}
}
The error message is confusing to you because you're specifying a type of a function parameter, but attempting to use the name of a value to do that. Your syntax is just completely invalid. The syntax SomeType::Something can make some sense, where Something is an associated type of some trait implemented by SomeType. This is the compiler's best guess of making sense of the syntax you gave it, so it's trying to correct you based on that. That syntax still wouldn't be correct, since you'd need the fully-qualified syntax indicated by the error message.
I'd like to save a record from PalletA in PalletB by simply passing the raw data and waiting for the return.
I have tried following:
// ./PalletB/lib.rs
pub trait PutInStorage {
fn put_rule_in_storage(value: u32);
}
impl<T: Trait> PutInStorage for Module<T> {
fn put_rule_in_storage(value: u32) {
SimpleCounter::put(value);
}
}
then in
// ./PalletA/lib.rs
use palletB::{PutInStorage, Trait as PalletBTrait};
///The pallet's configuration trait.
pub trait Trait: system::Trait + PalletBTrait {
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
type ExternalStorage: PutInStorage;
}
then I added the definition to the runtime like this:
// ./runtime/lib.rs
// near the construct_runtime macro
impl palletA::Trait for Runtime {
type Event = Event;
type ExternalStorage = palletB::Module<Runtime>;
}
So far this passes the check but not the test. The test configuration for the trait is like this:
use palletB::{PutInStorage, Trait as PalletBTrait};
impl Trait for Test {
type Event = ();
type ExternalStorage = PutInStorage;
}
and this fails with the:
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^ help: use `dyn`: `dyn PutInStorage`
impl Trait for Test
------------------- in this `impl` item
type Event = ();
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pallet_rules::PutInStorage` cannot be made into an object
I tried all the suggestions the Rust compiler gives me but without any luck. Before someone asks why do I need this in my test, it's because a dispatchable fn in decl_module! checks does a certain record exists before starts processing and saving its own records. It is dependent on record to exist.
To make the compiler happy, your test config must also have an instance of PalletB, or anything else that implements PutInStorage.
Similar to what you've done already in ./runtime/lib.rs:
impl Trait for Test {
type Event = ();
type ExternalStorage = palletB::Module<Test>;
}
Note that now struct Test is the one playing the role of Runtime. I think this is the only thing that you are missing.
That being said, you seem to be on the wrong track in the overall design.
PalletA already depends on PalletB. Given that you also have a trait to link the two PutInStorage, this is not a good design. Generally, you should try and always chose one of the following:
Two pallets will depend on one another. In this case you don't need traits. If one needs to put something to the storage of the other one, you just do it directly. In your example, I assume that PalletB has a storage item called pub Foo: u32 in decl_storage and PutInStorage writes to this. If this is the case, there's no need for a trait. From PalletA you can just say: palletB::Foo::put(value).
Note that this approach should be chosen with care, otherwise you might end up with a lot of pallets depending on one another which is not good.
You decide that your pallets do NOT depend on one another, in which case you use some trait like PutInStorage. Your code seem to be aligned with this approach, except you define PalletA's Trait as pub trait Trait: system::Trait. There's no need to depend on PalletB here, and of course you can wipe it from Cargo.toml as well.
As part of mapping a C interface to Rust, I want to handle a union that stored a few native types directly and have a pointer to an allocated type for all others.
How can I implement a parameterized wrapper type around the union that can select and use the appropriate field based on the wrapper type parameter?
In this case, I want to add a Rust wrapper that reads the data structure directly and not a solution that converts it to a Rust-native type first. Adding other support types to "trick" the compiler is fine though. The end goal is to be able to write code similar to this:
let the_list: List<i32> = get_a_list();
for i in the_list {
println!("value")
}
I am skipping the definitions of IntoIterator and friends since that boils down to accessing the correct field based on the type.
The code is highly unsafe, but we can assume that the user provides the correct type for the type parameter.
There are other solutions to this problem such as having explicit reader functions for each type, but this is focused on understanding if there are ways to make it work without those and without introducing an undue overhead.
Code that does not work, but illustrates what I want to accomplish:
#![feature(specialization)]
use std::convert::From;
union Data<T> {
int_value: i64,
ptr_value: *const T,
}
default impl<T> From<&Data<T>> for &T {
fn from(data: &Data<T>) -> &T {
&*data.ptr_value
}
}
impl From<&Data<i64>> for &i64 {
fn from(data: &Data<i64>) -> &i64 {
&*data.int_value
}
}
fn show<T>(value: &T) {
println!("value: {}", value);
}
fn main() {
let value = String::from("magic");
let data: Data<&str> = Data {
ptr_value: value.as_ptr(),
};
show(data.into());
}
I have minimized the example to avoid discussions about other aspects. This gives the following error:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> examples/union_convert.rs:10:14
|
10 | default impl<T> From<&Data<T>> for &T {
| ^ type parameter `T` must be used as the type parameter for some local type
|
= note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
I have tried adding a wrapper around the union to handle the type-punning, but that seems to just push the error message around. Returning some other type than &T would also be possible, but I do not understand how to make it behave correctly. Using a different return type is also an option, but it still boils down to selecting the correct field based on a type.
Looking at the implementation of std::vec::Vec it does a similar thing, but in this case it always map the memory representation of the type to a real type. In this case, I want to select the correct union field based on the type that was used when writing the value.
Other similar questions that do not really answer this questions:
How to force a union to behave as if there is only one type? ask a similar question, but in this case there are explicit functions to retrieve each type and in this case I want to use the type to resolve what field to read.
Resolve union structure in Rust FFI just address the issue that you need to explicitly pick what field to read, which is what I intend to do.
How is there a conflicting implementation of From when using a generic type? This question discuss From as well, but it converting from a generic type (e.g., &T) to the implemented type (e.g., Data<T>). This question is about going in the other direction: converting from a new type (Data<T>) to a more generic type (&T).
Update: Provided a more distinct example of using into() to convert the union type one of the fields.
I would define my own trait instead of From to avoid conflicting with the standard library implementations. I'd also define a newtype wrapper / marker type. This removes the possibility of conflict when storing one of the specific types in the generic spot.
struct Other<T>(T);
union Data<T> {
bool_value: bool,
int_value: i64,
ptr_value: *const T,
}
trait Access<T> {
type Output;
unsafe fn access(&self) -> &Self::Output;
}
impl<T> Access<Other<T>> for Data<T> {
type Output = T;
unsafe fn access(&self) -> &Self::Output {
&*self.ptr_value
}
}
impl<T> Access<bool> for Data<T> {
type Output = bool;
unsafe fn access(&self) -> &Self::Output {
&self.bool_value
}
}
impl<T> Access<i64> for Data<T> {
type Output = i64;
unsafe fn access(&self) -> &Self::Output {
&self.int_value
}
}
fn main() {
let value = 123_f64;
let data: Data<f64> = Data { ptr_value: &value };
// This is safe because we just created this with
// a `f64` and nothing happened in-between.
unsafe {
println!("{}", Access::<Other<f64>>::access(&data));
}
}
See also:
How is there a conflicting implementation of `From` when using a generic type?
In my short Rust experience I ran into this pattern several times, and I'm not sure if the way I solve it is actually adequate...
Let's assume I have some trait that looks like this:
trait Container {
type Item;
fn describe_container() -> String;
}
And some struct that implements this trait:
struct ImAContainerType;
struct ImAnItemType;
impl Container for ImAContainerType {
type Item = ImAnItemType;
fn describe_container() -> String { "some container that contains items".to_string() }
}
This may be a container that has a knowledge about type of items it contains, like in this example, or, as another example, request which knows what type of response should be returned, etc.
And now I find myself in a situation, when I need to implement a function that takes an item (associated type) and invokes a static function of the container (parent trait). This is the first naive attempt:
fn describe_item_container<C: Container>(item: C::Item) -> String {
C::describe_container()
}
This does not compile, because associated types are not injective, and Item can have several possible Containers, so this whole situation is ambiguous. I need to somehow provide the actual Container type, but without providing any container data. I may not have the container data itself at all when I invoke this function!
In search for a solution, I find the documentation for std::marker::PhantomData. It says:
PhantomData allows you to describe that a type acts as if it stores a value of type T, even though it does not.
This has to be the Rust's replacement for Haskell's Proxy type, right? Let's try to use it:
fn describe_item_container<C: Container>(container: PhantomData<C>, item: C::Item) -> String {
C::describe_container()
}
let s = describe_item_container(PhantomData::<PhantomData<ImAContainerType>>, ImAnItemType);
println!("{}", s);
Compiling... Error:
error[E0277]: the trait bound `std::marker::PhantomData<ImAContainerType>: Container` is not satisfied
I ask #rust-beginners and get a response: PhantomData is not meant to be used that way at all! Also I got an advice to simply make a backward associated type link from Item to Container. Something like this:
trait Item {
type C: Container;
}
fn describe_item_container<I: Item>(item: I) -> String {
I::C::describe_container()
}
It should work, but makes things much more complicated (especially for cases when item can be placed in different container kinds)...
After a lot more experimentation, I do the following change and everything compiles and works correctly:
let s = describe_item_container(PhantomData::<ImAContainerType>, ImAnItemType);
println!("{}", s);
The change is ::<PhantomData<ImAContainerType>> to ::<ImAContainerType>.
Playground example.
It works, but now I'm completely confused. Is this the correct way to use PhantomData? Why does it work at all? Is there some other, better way to provide type-only argument to a function in Rust?
EDIT: There is some oversimplification in my example, because in that particular case it would be easier to just invoke ImAContainerType::describe_container(). Here is some more complicated case, when the function actually does something with an Item, and still requires container type information.
If you want to pass a type argument to a function, you can just do it. You don't have to leave it out to be inferred.
This is how it looks for your second example (playground):
fn pack_item<C: Container>(item: C::Item) -> ItemPacket {
ItemPacket {
container_description: C::describe_container(),
_payload: item.get_payload(),
}
}
fn main() {
let s = pack_item::<ImAContainerType>(ImAnItemType);
println!("{}", s.container_description);
let s = pack_item::<ImAnotherContainerType>(ImAnItemType);
println!("{}", s.container_description);
}
I'd like to create a generic tuple struct Producer which can hold any type P which implements the trait Produce<T>, defined below. This produces the (expected) commented error:
trait Produce<T> {
fn get(&mut self) -> T;
}
// ERROR: parameter `T` is never used [E0392]
struct Producer<P,T>(P) where P: Produce<T>;
If this were a non-tuple struct, I could remedy this issue by adding a PhantomData<T> field and writing a constructor Producer::new(p: P) to hide this as an implementation detail. However, I'm using this type as one of a family of tuple structs in a Builder API, so using a conventional struct + constructor feels pretty out of place.
Is there any way to achieve this?
In many cases, you don't want to parameterize your trait, but instead want an associated type:
trait Produce {
type T;
fn get(&mut self) -> Self::T;
}
struct Producer<P>(P) where P: Produce;
fn main() {}
Unfortunately, it's tough to tell if this will work for you without knowing a lot more about the anticipated use case and code examples, which might be too verbose for Stack Overflow.