PhantomData type usage in rust - rust

I was going through some rust source code and I found a data type called PhantomData. I was going through the rust documentation and searched through the internet a lot. However, I couldn't understand the actual use of this data type with rust. If possible, could somebody please explain me this in simple manner?
pub struct GPIOD {
_marker: PhantomData<*const ()>,
}

The PhantomData struct is meant to signal to the compiler that a type or lifetime is being used in some way that is transparent to the compiler.
To quote the docs:
Adding a PhantomData field to your type tells the compiler that your type acts as though it stores a value of type T, even though it doesn't really. This information is used when computing certain safety properties.
For example, if we look at the iterator type for a slice [T]: std::slice::Iter<'a, T> and its declaration using the src button we'll see that it's actually declared as such:
struct Iter<'a, T: 'a> {
start: *const T,
end: *const T,
_phantom: PhantomData<&'a T>,
}
std makes frequent use of pointer arithmetic to make optimizations more readily available (Although that is not to endorse the usage of pointer arithmetic in user code). In this case, we need to assure ourselves that the data that is pointed to by the two raw pointers (Which carry no lifetimes) outlive the struct, so we keep a PhantomData<&'a T> to tell the compiler to act like as if Iter owned a &'a T therefore enforcing lifetime rules for it.

In addition to the other answer, I'd like to add an example. As said in the other answer, PhantomData allows to add an arbitrary lifetime dependence between 2 structure.
Suppose that you have a struct that manages a logging tool with a message receiver, and a struct that represents an actual logger that sends messages to the manager. Although the logger does not directly depends on the manager, the manager must outlive the logger to prevent send errors.
The naive code does not create any dependency between the 2 structs:
struct LogManager {
// ...
}
impl LogManager {
fn logger(&self) -> Logger {
// returns a fresh `Logger` that holds no reference to `LogManager`...
}
}
struct Logger {
// ...
}
Now, if the Logger holds a phantom reference, we can force a dependency between the 2 structs:
struct Logger<'a> {
// ...
_marker: PhantomData<'a ()>,
}
and in the impl block:
impl LogManager {
fn logger(&self) -> Logger {
Logger {
// ...
// Here, `Logger` will have a lifetime dependent of the `LogManager`'s
// lifetime due to `PhantomData`:
_marker: PhantomData,
}
}
}
Now, no instance of Logger can outlive the LogManager where it comes from.

Related

How do I avoid Enum + Trait pattern when a struct is not object safe?

I get the implications of object safety, but I'm trying to find an idiomatic way to solve for this situation.
Say I have two structs that share common behavior and also need to derive PartialEq for comparison in another part of the program:
trait Growl:PartialEq {
fn growl(&self);
}
#[derive(PartialEq)]
struct Pikachu;
#[derive(PartialEq)]
struct Porygon;
impl Growl for Pikachu {
fn growl(&self) {
println!("pika");
}
}
impl Growl for Porygon {
fn growl(&self) {
println!("umm.. rawr?");
}
}
In another struct, I want to hold a Vec of these objects. Since I can't use a trait object with Vec<Box<Growl>>...
struct Region{
pokemon: Vec<Box<dyn Growl>>,
}
// ERROR: `Growl` cannot be made into an object
... I need to get more creative. I read this article, which suggests using an enum or changing the trait. I haven't yet explored type erasure, but it seems heavy-handed for my use case. Using an enum like this is what I've ended up doing but it feels unnecessarily complex
enum Pokemon {
Pika(Pikachu),
Pory(Porygon),
}
Someone coming through this code in the future now needs to understand the individual structs, the trait (which provides all functionality for the structs), and the wrapper enum type to make changes.
Is there a better solution for this pattern?
I read this article, which suggests using an enum or changing the trait. I haven't yet explored type erasure, but it seems heavy-handed for my use case.
Type erasure is just a synonym term for dynamic dispatch - even your original Box<dyn Growl> "erases the type" of the Pokemon. What you want here is to continue in the same vein, by creating a new trait better taylored to your use case and providing a blanket implementation of that trait for any type that implements the original trait.
It sounds complex, but it's actually very simple, much simpler than erased-serde, which has to deal with serde's behemoth traits. Let's go through it step by step. First, you create a trait that won't cause issues with dynamic dispatch:
/// Like Growl, but without PartialEq
trait Gnarl {
// here you'd have only the methods which are actually needed by Region::pokemon.
// Let's assume it needs growl().
fn growl(&self);
}
Then, provide a blanket implementation of your new Gnarl trait for all types that implement the original Growl:
impl<T> Gnarl for T
where
T: Growl,
{
fn growl(&self) {
// Here in the implementation `self` is known to implement `Growl`,
// so you can make use of the full `Growl` functionality, *including*
// things not exposed to `Gnarl` like PartialEq
<T as Growl>::growl(self);
}
}
Finally, use the new trait to create type-erased pokemon:
struct Region {
pokemon: Vec<Box<dyn Gnarl>>,
}
fn main() {
let _region = Region {
pokemon: vec![Box::new(Pikachu), Box::new(Porygon)],
};
}
Playground

function "optional trait bound" in rust

I want to have something like optional trait bound for function. Where if T implements that type - do something.
fn test<T: Eq + ?Debug>(a:T, b:T){
if a!=b{
println!("Not equal!");
if (T impl Debug){
println!("{:?} != {:?}", a, b);
}
}
}
As #user4815162342 commented, using specialization, this is possible.
I'll provide a slightly different approach from what they specified in their comment, to keep the same if ... { ... } setup that you had in your original code.
The idea is to have a trait AsMaybeDebug with an associated type Debug, which always implements Debug and a function to go from &Self to Option<&Self::Debug>:
trait AsMaybeDebug {
type Debug: Debug;
fn as_maybe_debug(&self) -> Option<&Self::Debug>;
}
After this we make a default impl for all T, with the debug type being !, the never type, and always return None.
impl<T> AsMaybeDebug for T {
default type Debug = !;
default fn as_maybe_debug(&self) -> Option<&Self::Debug> {
None
}
}
Instead of the never type, you could choose any type that always implemented Debug but still returning None.
Afterwards we specialize for T: Debug by returning Self:
impl<T: Debug> AsMaybeDebug for T {
type Debug = Self;
fn as_maybe_debug(&self) -> Option<&Self::Debug> {
Some(self)
}
}
Finally in test we just call as_maybe_debug and check if T: Debug
fn test<T: Eq>(a: T, b: T){
if a != b {
println!("Not equal!");
if let (Some(a), Some(b)) = (a.as_maybe_debug(), b.as_maybe_debug()) {
println!("{:?} != {:?}", a, b);
}
}
}
You can check in the playground both that it works and that the assembly generated for test_non_debug doesn't have any debugging calls, only the single call to std::io::_print.
It unfortunately isn't possible to retrieve the original a or b inside the if after calling as_maybe_debug.
This is due to <Self as AsMaybeDebug>::Debug not being
convertible back to Self.
This can be fixed, but not easily as it requires updates from the standard library.
Requiring AsMaybeDebug::Debug: AsRef<Self> doesn't work for 2 reasons:
There is no impl<T> AsRef<T> for T yet, this is due to specialization still being incomplete, I assume.
There is no impl<T> AsRef<T> for ! yet. Not sure if this impl can be made even with specialization or not, but it would be required.
Also, although the specialization can be unsound, I believe that the trait and it's impls cannot be used for unsoundness, you would need a specific setup to be able to generate unsoundness from it, which this lacks.
As mentioned in the comments, you're looking for the impls crate, which does exactly what you want.
if impls!(T: Debug) {
...
}
Just for the sake of completeness, here's how you do it without an external crate dependency. I'm paraphrasing from the way the impls developer explains the trick.
Let's say we want to check whether some type implements Debug. First, let's define the "base case".
trait NotDebug {
const IMPLS: bool = false;
}
We'll also provide a blanket implementation so that all types (which don't have a better answer) have a IMPLS constant equal to false.
impl<T> NotDebug for T {}
Now, let's make a simple type with a single generic type parameter.
struct IsDebug<T>(std::marker::PhantomData<T>);
PhantomData is conceptually nonexistent and exists only to anchor the generic type T to our IsDebug. We can think of IsDebug as being effectively a singleton struct.
Now, we would like IsDebug::<T>::IMPLS to be true if (and only if) T implements Debug. Currently, IsDebug::<T>::IMPLS is always false, by a blanket implementation of NotDebug. But we can specify an inherent impl that applies conditionally.
impl<T: Debug> IsDebug<T> {
const IMPLS: bool = true;
}
Since this is an impl on IsDebug itself, not on a trait implementation, it takes precedent over the NotDebug blanket implementation. In any case where T: Debug, the inherent impl kicks in and we get true. In any other case, the inherent impl fails, so we get the fallback blanket implementation which gives false.
Try it in the Rust Playground!

How to assign an impl trait in a struct?

Consider some struct (HiddenInaccessibleStruct) that is not accessible, but implements an API trait. The only way to obtain an object of this hidden type is by calling a function, that returns an opaque implementation of this type. Another struct owns some type, that makes use of this API trait. Right now, it seems not possible to assign this field in fn new(). The code below can also be found in rust playgrounds.
// -- public api
trait Bound {
fn call(&self) -> Self;
}
// this is not visible
#[derive(Default)]
struct HiddenInaccessibleStruct;
impl Bound for HiddenInaccessibleStruct {
fn call(&self) -> Self { }
}
// -- public api
pub fn load() -> impl Bound {
HiddenInaccessibleStruct::default()
}
struct Abc<T> where T : Bound {
field : T
}
impl<T> Abc<T> where T : Bound {
pub fn new() -> Self {
let field = load();
Abc {
field // this won't work, since `field` has an opaque type.
}
}
}
Update
The API trait Bound declares a function, that returns Self, hence it is not Sized.
There are two concepts in mid-air collision here: Universal types and existential types. An Abc<T> is a universal type and we, including Abc, can refer to whatever T actually is as T (simple as that). impl Trait-types are Rust's closest approach to existential types, where we only promise that such a type exists, but we can't refer to it (there is no T which holds the solution). This also means your constructor can't actually create a Abc<T>, because it can't decide what T is. Also see this article.
One solution is to kick the problem upstairs: Change the constructor to take a T from the outside, and pass the value into it:
impl<T> Abc<T>
where
T: Bound,
{
pub fn new(field: T) -> Self {
Abc { field }
}
}
fn main() {
let field = load();
let abc = Abc::new(field);
}
See this playground.
This works, but it only shifts the problem: The type of abc in main() is Abc<impl Bound>, which is (currently) impossible to write down. If you change the line to let abc: () = ..., the compiler will complain that you are trying to assign Abc<impl Bound> to (). If you try to comply with the advice and change the line to let abc: Abc<impl Bound> = ..., the compiler will complain that this type is invalid. So you have to leave the type of abc being implied. This brings some useability issues with Abc<impl Bound>, because you can't easily put values of that type into other structs etc.; basically, the existential type "infects" the outer type containing it.
impl Trait-types are mostly useful for immediate consumption, e.g. impl Iterator<Item=...>. In your case, with the aim apparently being to hide the type, you may get away with sealing Bound. In a more general case, it may be better to use dynamic dispatch (Box<dyn Bound>).

How to offer an API that stores values of different types and can return them with the original type restored?

I want to offer a safe API like below FooManager. It should be able to store arbitrary user-defined values that implement a trait Foo. It should also be able to hand them back later - not as trait object (Box<dyn Foo>) but as the original type (Box<T> where T: Foo). At least conceptually it should be possible to offer this as a safe API, by using generic handles (Handle<T>), see below.
Additional criteria:
The solution should work in stable Rust (internal usage of unsafe blocks is perfectly okay though).
I don't want to modify the trait Foo, as e.g. suggested in How to get a reference to a concrete type from a trait object?. It should work without adding a method as_any(). Reasoning: Foo shouldn't have any knowledge about the fact that it might be stored in containers and be restored to the actual type.
trait Foo {}
struct Handle<T> {
// ...
}
struct FooManager {
// ...
}
impl FooManager {
// A real-world API would complain if the value is already stored.
pub fn keep_foo<T: Foo>(&mut self, foo: Box<T>) -> Handle<T> {
// ...
}
// In a real-world API this would return an `Option`.
pub fn return_foo<T: Foo>(&mut self, handle: Handle<T>) -> Box<T> {
// ...
}
}
I came up with this (Rust Playground) but not sure if there's a better way or if it's safe even. What do you think of that approach?

How can I share references across threads?

I am unable to share a reference between threads.
trait Facade { /*some functions*/ }
struct Client<'a> {
facade: &'a mut Facade,
join_grd: thread::JoinGuard<'a()>,
}
impl<'a> Client<'a> {
pub fn new(my_facade: &'a mut Facade) -> Client<'a> {
Client {
facade: my_facade,
join_grd: thread::scoped(|| Client::start(my_facade)),
}
}
fn start(my_facade: &'a mut Facade) { unimplemented!() }
}
Given my newbie status in Rust, I'm getting confused with concepts and errors. How do I achieve the above ?
I'm pretty sure you can't do this due to the mutable aliasing guarantees in Rust. In Rust you can't have two mutable references to the same thing at the same time, but this is exactly what happens in your code: you store my_facade to the field of Client and at the same time you are trying to pass it to start() method in another thread. This would require having two mutable references to the same Facade which is disallowed.
The actual errors which compiler emits on your code are caused by that you're using a non-moving closure. If you change thread::scoped() instantiation to this:
join_grd: thread::scoped(move || Client::start(my_facade))
the error would be more sensible:
test.rs:16:60: 16:69 error: cannot move `my_facade` into closure because it is borrowed
test.rs:16 join_grd: thread::scoped(move || Client::start(my_facade))
^~~~~~~~~
test.rs:15:21: 15:30 note: borrow of `*my_facade` occurs here
test.rs:15 facade: my_facade,
^~~~~~~~~
This essentially means that since &mut references are unique and are moved instead of copied, you can't duplicate them. Similar code with the regular & reference instead of &mut (and an additional Sync parent trait on Facade) works fine.
You have to rethink your architecture to fix this error. It is difficult to understand what you want from this piece of code alone, so I can't give any exact advices, but you may consider using Arc and Mutex if you want to share mutable state between threads.
Naive usage of Arc/Mutex like this:
fn start(my_facade: Arc<Mutex<Facade>>)
won't work because Facade is a trait, not a regular type. When you use traits as types, you're in fact opting into dynamic dispatch in form of trait objects. In short, trait objects can't be used directly; they should always be behind a pointer. Your original program also used trait objects (&'a mut Facade is a trait object). Ideally we should be able to form trait objects with any kind of smart pointer, and ideally Arc<Mutex<Facade>> should work, but unfortunately for now trait objects can only be created with &, &mut or Box:
fn start(my_facade: Arc<Mutex<Box<Facade>>>)
This is the reason of the error about Sized that you observe.
However, you should also consider not using trait objects at all and just use generics:
trait Facade: Send { fn f(&self); }
struct Client<'a, F: Facade> { // '
facade: Arc<Mutex<F>>,
join_grd: thread::JoinGuard<'a, ()>, // '
}
impl<'a, F: Facade+'a> Client<'a, F> { // '
pub fn new(my_facade: Arc<Mutex<F>>) -> Client<'a, F> { // '
let my_facade_2 = my_facade.clone(); // clone the Arc pointer
Client {
facade: my_facade,
join_grd: thread::scoped(move || Client::start(my_facade_2)),
}
}
fn start(my_facade: Arc<Mutex<F>>) { unimplemented!() }
}
You also need to add Send bound either on the trait itself (as in the example above) or on F type variable (as in F: Facade+Send+'a) because only Send data may be transferred between threads safely, so you need to specify that F is Send, either directly or as a supertrait constraint on Facade.

Resources