How does `Cow::Owned` implemented the `FnOnce`? - 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

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

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

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.

How to write a trait method taking an iterator of strings, avoiding monomorphization (static dispatch)?

I want to define a trait that has a method operating on sequences of strings. At the same time, I want to avoid having generic methods, a.k.a. static dispatch, in the trait, so that I can use this trait as a trait object. The best solution I was given till now was to do it like below:
pub trait Store {
fn query_valid_paths(&mut self, paths: &mut dyn Iterator<Item = &str>) -> Vec<String>;
}
Unfortunately, it's not perfect:
It works out of the box only for iterators of &str; for iterators of String, e.g. Vec<String>, I have to call it with the following magic map incantation, which is really ugly, and I'd never invent it as a newbie without help:
// `vec` is a std::vec::Vec<String>
store.query_valid_paths(&mut vec.iter().map(|s| &**s));
It takes an Iterator, but I'd love if I could take an IntoIterator. In other words, I'd like to be able to call it just like this:
store.query_valid_paths(&vec);
Is it possible?
Failed Attempt 1
Based on a simpler question about functions taking string iterators, I'd imagine something like this could work:
pub trait Store {
fn query_valid_paths<S>(&mut self, paths: impl IntoIterator<Item = S>) -> Vec<String>
where
S: AsRef<str>;
}
but this seems to make it a "generic method", triggering static dispatch...
Failed Attempt 2
I was suggested another idea on Rust discord, specifically:
pub trait Store {
fn query_valid_paths_inner(&mut self, paths: &mut dyn Iterator<Item = &str>) -> Vec<String>;
}
impl dyn Store {
pub fn query_valid_paths<'a>(&mut self, paths: impl IntoIterator<Item = &'a str>) -> Vec<String> {
let mut it = paths.into_iter();
self.query_valid_paths_inner(&mut it)
}
}
— but when I try to add AsRef<str> to it, I'm getting lifetime errors, and cannot seem to make it work for both String and &str iterators...
I recommend you read this question, which has lots of good information about why you can't use generics with trait methods if you want to use them as objects.
The short answer is that you can't do what you're trying to do: have a function that takes in an iterator of any type (which is an associated generic function) and still have the trait be object safe.
There are a few tricks you can use, though, that will let you manipulate string iterators with a trait object. I'll go over each method.
1. Use multiple methods in your trait
Rust only has two kinds of strings: String and &str. As you've stated in your answer, you want to work with both. In this case, all you need to do is make two different methods:
pub trait Store {
fn query_valid_paths_str(&mut self, paths: &mut dyn Iterator<Item = &str>) -> Vec<String>;
fn query_valid_paths_string(&mut self, paths: &mut dyn Iterator<Item = String>) -> Vec<String>;
}
Now, this gets counter-intuitive at a certain point, if you have too many types you're dealing with. But if there's only two, this is the most straightforward option.
If you're wanting to use IntoIterator instead, the function signatures will look like this:
pub trait Store {
fn query_valid_paths_str(&mut self, paths: &mut dyn IntoIterator<IntoIter = IntoIter<&str>, Item = &str>) -> Vec<String>;
fn query_valid_paths_string(&mut self, paths: &mut dyn IntoIterator<IntoIter = IntoIter<String>, Item = String>) -> Vec<String>;
}
2. Use Box and dynamic dispatch
This approach is much more involved, and probably not worth the effort, but I'll put it here as a proof of concept.
pub trait Store {
fn query_valid_paths(&mut self, paths: &mut dyn Iterator<Item = &Box<dyn AsRef<str>>) -> Vec<String>;
}
Here, paths is an iterator over a box which owns an AsRef<str> trait object.
This is (as far as I know) the only way to create a truly polymorphic solution. But at what cost? For this to work, you not only need to explicitly declare the list you passed in as a Vec<Box<AsRef<str>>>, it adds a lot of overhead with dynamic dispatch from the box pointers. Just to show how cumbersome this can be:
let mut str_vec: Vec<Box<AsRef<str>>> = vec!(Box::new("string one"), Box::new("string two".to_string()));
some_store_object.query_valid_paths(&mut str_vec.iter());
I do not recommend this method unless you absolutely need this functionality. Use the first method instead.
If you do use this method, but want to use it with IntoIterator, it would look like this:
pub trait Store {
fn query_valid_paths(&mut self, paths: &mut dyn IntoIterator<IntoIter = IntoIter<Box<dyn AsRef<str>>>, Item = Box<dyn AsRef<str>>>) -> Vec<String>;
}
I don't think there is a nice solution without static dispatch. But the docs for the error about trait objects with methods with generic parameters actually provide a solution for this situation:
First, you mark your method with where Self: Sized – this makes it unavailable in trait objects. Maybe you don't need that method in trait object context – then you're done here.
If you need the method in trait object context, you can make it usable again via a sized type that contains your trait object e.g. Box:
struct MyStruct(i32);
pub trait Store {
fn len_of_first_str(&self, paths: impl IntoIterator<Item = impl AsRef<str>>) -> usize
where Self: Sized{
paths.into_iter().next().unwrap().as_ref().len()
}
}
impl Store for Box<dyn Store>{}
fn myfun(arg: Box<dyn Store>) -> usize {
arg.len_of_first_str(vec!["string"])
}
Besides the Box approach, it is possible to define the generic in the trait definition. This method is limited by the type being implemented and uses static dispatch but your trait won't break the rules of object safety.
trait Store<'a, I>
where
I: IntoIterator<Item = &'a str>,
{
fn query_valid_paths(&mut self, iter: I) -> Vec<String>;
}
impl<'a, I> Store<'a, I> for ()
where
I: IntoIterator<Item = &'a str>,
{
fn query_valid_paths(&mut self, iter: I) -> Vec<String> {
iter.into_iter().map(|x| x.to_string()).collect()
}
}
// Store is object safe
struct _Bar<'a, I> {
vec: Vec<Box<dyn Store<'a, I>>>,
}
fn main() {
let vec_of_strings = vec!["one", "two", "three"];
println!("{:?}", ().query_valid_paths(vec_of_strings));
}
To avoid taking ownership, you can use vec_of_strings.iter().cloned() instead.

Resources