Is an enum variant instance also a closure in Rust? [duplicate] - rust

This example works fine.
use std::borrow::Cow;
fn main() {
let a = Some("Hello");
let b: Option<Cow<&'static str>> = a.map(Cow::Owned);
println!("{:?}", b);
}
The Option map requires the param must implement FnOnce(T) -> U:
pub const fn map<U, F>(self, f: F) -> Option<U>
where
F: ~const FnOnce(T) -> U,
F: ~const Destruct,
{
match self {
Some(x) => Some(f(x)),
None => None,
}
}
I want to figure out how Cow::Owned implement the FnOnce. I have searched the source code and found nothing helpful.
Any idea about this?

Every tuple struct or tuple enum variant with public members is also a free-standing function:
pub struct A(pub u8);
// creates essentially
pub fn A_fn(one: u8) {
A(one) // returns the struct
}
Every free-standing fn falls under the Fn category. FnMut and FnOnce are pretty much only ever applicable to closures.
Any closure which is categorized under Fn can be used in a place requiring FnMut or FnOnce. Any closure which is categorized under FnMut can be used in a place requiring FnOnce, but NOT in a place requiring Fn. Any function or closure which is categorized under FnOnce can ONLY be used in a place requiring just FnOnce.
In this way, when you see a Fn bound, it's actually the opposite in terms of restriction. FnOnce is actually the most permissive bound:
: Fn means that only Fn closures can be used there
: FnMut means that only Fn or FnMut closures can be used there
: FnOnce means that Fn, FnMut, or FnOnce closures can be used there
Cow::Owned is a tuple enum variant with only public members, so can be used as if it were fn(B) -> Cow<'_, B>. And since Fn can be used where there's a FnOnce bound, it's accepted.

Related

How does `Cow::Owned` implemented the `FnOnce`?

This example works fine.
use std::borrow::Cow;
fn main() {
let a = Some("Hello");
let b: Option<Cow<&'static str>> = a.map(Cow::Owned);
println!("{:?}", b);
}
The Option map requires the param must implement FnOnce(T) -> U:
pub const fn map<U, F>(self, f: F) -> Option<U>
where
F: ~const FnOnce(T) -> U,
F: ~const Destruct,
{
match self {
Some(x) => Some(f(x)),
None => None,
}
}
I want to figure out how Cow::Owned implement the FnOnce. I have searched the source code and found nothing helpful.
Any idea about this?
Every tuple struct or tuple enum variant with public members is also a free-standing function:
pub struct A(pub u8);
// creates essentially
pub fn A_fn(one: u8) {
A(one) // returns the struct
}
Every free-standing fn falls under the Fn category. FnMut and FnOnce are pretty much only ever applicable to closures.
Any closure which is categorized under Fn can be used in a place requiring FnMut or FnOnce. Any closure which is categorized under FnMut can be used in a place requiring FnOnce, but NOT in a place requiring Fn. Any function or closure which is categorized under FnOnce can ONLY be used in a place requiring just FnOnce.
In this way, when you see a Fn bound, it's actually the opposite in terms of restriction. FnOnce is actually the most permissive bound:
: Fn means that only Fn closures can be used there
: FnMut means that only Fn or FnMut closures can be used there
: FnOnce means that Fn, FnMut, or FnOnce closures can be used there
Cow::Owned is a tuple enum variant with only public members, so can be used as if it were fn(B) -> Cow<'_, B>. And since Fn can be used where there's a FnOnce bound, it's accepted.

Understanding "the trait X cannot be made into an object" for `&mut Box<Self>` parameter

I've got this code snippet (playground):
struct TeddyBear {
fluffiness: u8,
}
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy>;
}
impl Scruffy for TeddyBear {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> {
// do something about the TeddyBear's fluffiness
}
}
It doesn't compile. The error is:
the trait Scruffy cannot be made into an object
, along with the hint:
because method scruff_up's self parameter cannot be dispatched on.
I checked the "E0038" error description, but I haven't been able to figure out which category my error falls into.
I also read the "object-safety" entry in "The Rust Reference", and I believe this matches the "All associated functions must either be dispatchable from a trait object", but I'm not sure, partly because I'm not sure what "receiver" means in that context.
Can you please clarify for me what's the problem with this code and why it doesn't work?
The problem is when you pass it in as a reference, because the inner type may not be well-sized (e.g. a trait object, like if you passed in a Box<Fluffy>) the compiler doesn't have enough information to figure out how to call methods on it. If you restrict it to sized objects (like your TeddyBear) it should compile
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> where Self: Sized;
}
A receiver is the self (&self, &mut self, self: &mut Box<Self> and so on).
Note that the list you cited from the reference lists both Box<Self> and &mut Self, but does not list &mut Box<Self> nor it says that combinations of these types are allowed.
This is, indeed, forbidden. As for the why, it is a little more complex.
In order for a type to be a valid receiver, it needs to hold the following condition:
Given any type Self that implements Trait and the receiver type Receiver, the receiver type should implement DispatchFromDyn<dyn Trait> for itself with all Self occurrences of Self replaced with dyn Trait.
For instance:
&self (has the type &Self) has to implement DispatchFromDyn<&dyn Trait>, which it does.
Box<Self> has to implement DispatchFromDyn<Box<dyn Trait>>, which it does.
But in order for &mut Box<Self> to be an object-safe receiver, it would need to impl DispatchFromDyn<&mut Box<dyn Trait>>. What you want is kind of blanket implementation DispatchFromDyn<&mut T> for &mut U where U: DispatchFromDyn<T>.
This impl will never exist. Because it is unsound (even ignoring coherence problems).
As explained in the code in rustc that calculates this:
The only case where the receiver is not dispatchable, but is still a valid receiver type (just not object-safe), is when there is more than one level of pointer indirection. E.g., self: &&Self, self: &Rc<Self>, self: Box<Box<Self>>. In these cases, there is no way, or at least no inexpensive way, to coerce the receiver from the version where Self = dyn Trait to the version where Self = T, where T is the unknown erased type contained by the trait object, because the object that needs to be coerced is behind a pointer.
The problem is inherent to how Rust handles dyn Trait.
dyn Trait is a fat pointer: it is actually two words sized. One is a pointer to the data, and the other is a pointer to the vtable.
When you call a method on dyn Trait, the compiler looks up in the vtable, find the method for the concrete type (which is unknown at compilation time, but known at runtime), and calls it.
This all may be very abstract without an example:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
fn call_foo(v: &dyn Trait) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: &dyn Trait = v;
call_foo(v);
}
The compiler generates code like:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
struct TraitVTable {
foo: fn(*const ()),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: DynTraitRef) {
(self.1.foo)(self.0)
}
}
fn call_foo(v: DynTraitRef) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: DynTraitRef = (v as *const (), &TRAIT_FOR_UNIT_VTABLE);
call_foo(v);
}
Now suppose that the pointer to the value is behind an indirection. I'll use Box<&self> because it's simple but demonstrates the concept best, but the concept applies to &mut Box<Self> too: they have the same layout. How will we write foo() for impl Trait for dyn Trait?
trait Trait {
fn foo(self: Box<&Self>);
}
impl Trait for () {
fn foo(self: Box<&Self>) {}
}
struct TraitVTable {
foo: fn(Box<*const ()>),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: Box<DynTraitRef>) {
let concrete_foo: fn(Box<*const ()>) = self.1.foo;
let data: *const () = self.0;
concrete_foo(data) // We need to wrap `data` in `Box`! Error.
}
}
You may think "then the compiler should just insert a call to Box::new()!" But besides Box not being the only one here (what with Rc, for example?) and we will need some trait to abstract over this behavior, Rust never performs any hard work implicitly. This is a design choice, and an important one (as opposed to e.g. C++, where an innocent-looking statement like auto v1 = v; can allocate and copy 10GB by a copy constructor). Converting a type to dyn Trait and back is done implicitly: the first one by a coercion, the second one when you call a method of the trait. Thus, the only thing that Rust does for that is attaching a VTable pointer in the first case, or discarding it in the second case. Even allowing only references (&&&Self, no need to call a method, just take the address of a temporary) exceeds that. And it can have severe implications in unexpected places, e.g. register allocation.
So, what to do? You can take &mut self or self: Box<Self>. Which one to choose depends on whether you need ownership (use Box) or not (use a reference). And anyway, &mut Box<Self> is not so useful (its only advantage over &mut T is that you can replace the box and not just its contents, but when you do that that's usually a mistake).

How to create an `Iterable` trait for references in Rust?

I'm trying to create a trait that captures the iter function in slice as well as VecDeque, BTreeMap and HashMap. I'd like the implementer of this trait to be able to specify and implement their own iterator type, but it looks like this iterator type must have a lifetime argument, and that cannot be given as an associated type.
In more detail, here's what I wish was possible in Rust:
trait RefIterable<T>
where for<'a> (T: 'a) => (Self::Iter<'a>: Iterator<Item = &'a T>)
{
type Iter; // Has kind (lifetime -> type)
fn refs<'a>(&'a self) -> Self::Iter<'a>
}
If this was possible, the implementation could look like this
impl RefIterable<T> for Vec<T> {
type Iter<'a> = std::slice::Iter<'a, T>; // This is not valid Rust code.
fn refs<'a>(&'a self) -> std::slice::Iter<'a, T> {
self.as_slice().iter()
}
}
I'm still relatively new to Rust, so I'm asking if there's already a way to do this that I'm not aware of, or if there's a nice workaround for this situation. I'd imagine that this situation is not very rare.
(Using Box<dyn 'a + Iterator<Item = &'a T>> is my current workaround, but that prevents some optimization from happening.)
Edit:
EvilTak's answer is probably the best thing we can do right now. The ability to combine all possible lifetimes together with the condition T: 'a into one unparametrized trait seems to be unsupported by Rust as of today.
Add the lifetime parameter to the trait instead, which allows you to use it in the associated type Iter's bound:
trait RefIterable<'a> {
type Item: 'a;
type Iter: Iterator<Item = &'a Self::Item>; // Has kind (lifetime -> type)
fn refs(&'a self) -> Self::Iter;
}
The Item: 'a bound is required to let the compiler know that the references (&'a Self::Item) do not outlive the type (Self::Item).
I have modified RefIterable to make it follow Iterator's convention of using an associated type to specify the type of the items that are iterated over for the same reason as the one behind Iterator's usage of an associated type.
Implementations are pretty straightforward:
impl<'a, T: 'a> RefIterable<'a> for Vec<T> {
type Item = T;
type Iter = std::slice::Iter<'a, T>;
fn refs(&'a self) -> std::slice::Iter<'a, T> {
self.as_slice().iter()
}
}
Playground

Eliminate lifetime parameter from a trait whose implementation wraps a HashMap?

I'd like to wrap a few methods of HashMap such as insert and keys. This attempt compiles, and the tests pass:
use std::collections::HashMap;
use std::hash::Hash;
pub trait Map<'a, N: 'a> {
type ItemIterator: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::ItemIterator;
fn insert(&mut self, item: N);
}
struct MyMap<N> {
map: HashMap<N, ()>
}
impl<N: Eq + Hash> MyMap<N> {
fn new() -> Self {
MyMap { map: HashMap::new() }
}
}
impl<'a, N: 'a + Eq + Hash> Map<'a, N> for MyMap<N> {
type ItemIterator = std::collections::hash_map::Keys<'a, N, ()>;
fn items(&'a self) -> Self::ItemIterator {
self.map.keys()
}
fn insert(&mut self, item: N) {
self.map.insert(item, ());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Eq, Hash, PartialEq, Debug)]
struct MyItem;
#[test]
fn test() {
let mut map = MyMap::new();
let item = MyItem { };
map.insert(&item);
let foo = map.items().collect::<Vec<_>>();
for it_item in map.items() {
assert_eq!(it_item, &&item);
}
assert_eq!(foo, vec![&&item]);
}
}
I'd like to eliminate the need for the lifetime parameter in Map if possible, but so far haven't found a way. The problem seems to result from the definition of std::collections::hash_map::Keys, which requires a lifetime parameter.
Attempts to redefine the Map trait work until it becomes necessary to supply the lifetime parameter on Keys:
use std::collections::HashMap;
use std::hash::Hash;
pub trait Map<N> {
type ItemIterator: Iterator<Item=N>;
fn items(&self) -> Self::ItemIterator;
fn insert(&mut self, item: N);
}
struct MyMap<N> {
map: HashMap<N, ()>
}
impl<N: Eq + Hash> MyMap<N> {
fn new() -> Self {
MyMap { map: HashMap::new() }
}
}
// ERROR: "unconstrained lifetime parameter"
impl<'a, N> Map<N> for MyMap<N> {
type ItemIterator = std::collections::hash_map::Keys<'a, N, ()>;
}
The compiler issues an error about an unconstrained lifetime parameter that I haven't been able to fix without re-introducing the lifetime into the Map trait.
The main goal of this experiment was to see how I could also eliminate Box from previous attempts. As this question explains, that's another way to return an iterator. So I'm not interested in that approach at the moment.
How can I set up Map and an implementation without introducing a lifetime parameter or using Box?
Something to think about is that since hash_map::Keys has a generic lifetime parameter, it is probably necessary for some reason, so your trait to abstract over Keys will probably need it to.
In this case, in the definition of Map, you need some way to specify how long the ItemIterator's Item lives. (The Item is &'a N).
This was your definition:
type ItemIterator: Iterator<Item=&'a N>
You are trying to say that for any struct that implements Map, the struct's associated ItemIterator must be an iterator of references; however, this constraint alone is useless without any further information: we also need to know how long the reference lives for (hence why type ItemIterator: Iterator<Item=&N> throws an error: it is missing this information, and it cannot currently be elided AFAIK).
So, you choose 'a to name a generic lifetime that you guarantee each &'a N will be valid for. Now, in order to satisfy the borrow checker, prove that &'a N will be valid for 'a, and establish some useful promises about 'a, you specify that:
Any value for the reference &self given to items() must live at least as long as 'a. This ensures that for each of the returned items (&'a N), the &self reference must still be valid in order for the item reference to remain valid, in other words, the items must outlive self. This invariant allows you to reference &self in the return value of items(). You have specified this with fn items(&'a self). (Side note: my_map.items() is really shorthand for MyMap::items(&my_map)).
Each of the Ns themselves must also remain valid for as long as 'a. This is important if the objects contain any references that won't live forever (aka non-'static references); this ensures that all of the references that the item N contains live at least as long as 'a. You have specified this with the constraint N: 'a.
So, to recap, the definition of Map<'a, N> requires that an implementors' items() function must return an ItemIterator of references that are valid for 'a to items that are valid for 'a. Now, your implementation:
impl<'a, N: 'a + Eq + Hash> Map<'a, N> for MyMap<N> { ... }
As you can see, the 'a parameter is completely unconstrained, so you can use any 'a with the methods from Map on an instance of MyMap, as long as N fulfills its constraints of N: 'a + Eq + Hash. 'a should automatically become the longest lifetime for which both N and the map passed to items() are valid.
Anyway, what you're describing here is known as a streaming iterator, which has been a problem in years. For some relevant discussion, see the approved but currently unimplemented RFC 1598 (but prepare to be overwhelmed).
Finally, as some people have commented, it's possible that your Map trait might be a bad design from the start since it may be better expressed as a combination of the built-in IntoIterator<Item=&'a N> and a separate trait for insert(). This would mean that the default iterator used in for loops, etc. would be the items iterator, which is inconsistent with the built-in HashMap, but I am not totally clear on the purpose of your trait so I think your design likely makes sense.

How to use `Fn` trait with return type of `impl trait` in Rust?

I want to use Fn trait whose return type is impl Trait.
For example:
let funcs: [&Fn(&str) -> impl Iterator<Item = &str>] =
[&str::split_whitespace, &str::split_ascii_whitespace];
However, this code cannot be compiled with the below error message:
`impl Trait` not allowed outside of function and inherent method return types
How should I do?
str::split_whitespace and str::split_ascii_whitespace have different return types. You cannot construct an array of varying types. Instead, you can create an array of boxed trait objects. This will perform dynamic dispatch where the specific method called is determined at runtime (instead of static dispatch which is where the specific method version is known at compile-time)
Essentially, the goal is to have all the functions' signatures be:
for<'a> fn(&'a str) -> Box<dyn Iterator<Item=&'a str> + 'a>
which is a function that takes a &str and returns some iterator over &strs determined at runtime.
Now, this is where it starts getting messy and I hope someone can suggest a much better way to do this.
One way to get this to work is by creating wrapper functions around str::split_whitespace and str::split_ascii_whitespace to return a boxed trait instead of their respective SplitWhitespace and SplitAsciiWhitespace structs. I've used a helper macro to simply wrap the returned value from the function call in a Box
macro_rules! boxed_return {
($fn_new:ident, $fn:path) => {
fn $fn_new<'a>(s: &'a str) -> Box<dyn Iterator<Item=&'a str> + 'a> {
Box::new($fn(s))
}
}
}
boxed_return!(split_whitespace_wrapper, str::split_whitespace);
boxed_return!(split_ascii_whitespace_wrapper, str::split_ascii_whitespace);
Then we can simply create the array of splitter functions as follows
let funcs = [split_whitespace_wrapper, split_ascii_whitespace_wrapper];
Besides the fact that impl Trait can only be used in limited places syntactically right now, semantically it only means there will be one concrete type in it place. It is not a license for heterogeneous types or dynamic dispatching.
This can be done, but it is becoming unwieldy rather quickly:
type StrFn<'a> = &'a dyn Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>>;
fn main() {
let f1: StrFn = &|s: &'static str| Box::new(s.split_whitespace());
let f2: StrFn = &|s: &'static str| Box::new(s.split_ascii_whitespace());
let fs = vec![f1, f2];
fs[0]("rust 2020").for_each(|s| println!("{}", s));
}
Maybe there are better ways.

Resources