How do I create a Vec<T> where T: Into<_> in Rust? - rust

This is my example code. I am trying to pass a Vec<T> to a function where T: Into<_>!
enum Test {
FN(Box<dyn Fn()>),
STR(String),
}
impl<F> From<F> for Test
where F: Fn() + 'static
{
fn from(f: F) -> Self {
Self::FN(Box::new(f))
}
}
impl From<String> for Test {
fn from(s: String) -> Self {
Self::STR(s)
}
}
fn main() {
into(vec![
|| println!("func 1"),
|| println!("func 2"),
String::from("string 1"),
]);
}
fn into<T>(v: Vec<T>)
where T: Into<Test>
{
for test in v {
let test = test.into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The error is at the second closure:
expected closure, found a different closure
The problem is that Into<_> can't be dyn because it is Sized, so that doesn't work!
I am hoping for an output of:
func 1
func 2
string 1
Any answers or ideas?!

Rust does not generally do type coercion automatically. You've defined your From implementations, but nothing is calling them. You'd need to change your function to be more along the lines of
fn main() {
into(vec![
Test::from(|| println!("func 1")),
Test::from(|| println!("func 2")),
Test::from(String::from("string 1")),
]);
}

Just because you create a Test enum does not mean that Rust will reconcile the type of your otherwise heterogenous vector to be Test. You must manually instantiate each enum variant (and put a Box around your closures):
fn main() {
let x: Vec<Test> = vec![
Test::FN(Box::new(|| println!("func 1"))),
Test::FN(Box::new(|| println!("func 2"))),
Test::STR(String::from("string 1")),
];
into(x);
}

Your idea is to have a Vec of objects all being convertable to test. Yet Vec requires objects of the same type:
each closure has a different type
String is different from closure types
An example with a Vec with elements of the same type could be a Vecof just one of your elements:
into(vec![|| println!("func 1")]);
into(vec![|| println!("func 2")]);
into(vec![String::from("string 1")]);
// each has one element of ONE type, this compiles and runs
or a Vec of multiple elements of the same type:
into(vec![String::from("string 1"), String::from("string 2")]);
// each has multiple element of ONE type (String), this compiles and runs
To get your example to compile you will have to wrap your items in a wrapper type (e.g. an enum) that implements Into<Test>.
Your concrete example already contains such a wrapper type (Test) and thus your example unfortunately gets trivial, because if you put already Tests in your Vec you will not have to call into on them any more (this is shown in the other examples).

Thank you for all the answers,
I found my own solution by creating my own MyInto trait:
trait MyInto {
fn my_into(&self) -> Test;
}
enum Test<'l> {
FN(&'l dyn Fn()),
STR(String),
}
impl<F> MyInto for F
where F: Fn() + 'static
{
fn my_into(&self) -> Test {
Test::FN(self)
}
}
impl MyInto for String {
fn my_into(&self) -> Test {
Test::STR(self.to_owned())
}
}
fn main() {
into(vec![
&|| println!("func 1"),
&|| println!("func 2"),
&String::from("string 1"),
]);
}
fn into(v: Vec<&dyn MyInto>) {
for test in v {
let test = test.my_into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The output is now:
func 1
func 2
string 1
It is now possible to use the dyn in &dyn MyInto, because MyInto is not Sized!

Related

Cannot get wrapping of filter to compile

I have the goal of wrapping an Iterator<Item = rusb::Device<_> to Iterator<Item = LitraDevice>. The latter contains specific implementation.
To make this work I tried the following code:
use std::iter::Filter;
use rusb;
const VENDOR: u16 = 0x046d;
const PRODUCT: u16 = 0xc900;
struct LitraDevice {
dev: rusb::Device<rusb::GlobalContext>,
}
pub struct LitraDevices {
unfiltered: rusb::DeviceList<rusb::GlobalContext>,
}
struct LitraDeviceIterator<'a> {
it: Filter<rusb::Devices<'a, rusb::GlobalContext>, for<'r> fn(&'r rusb::Device<rusb::GlobalContext>) -> bool>,
}
impl LitraDevices {
pub fn new() -> Self {
let unfiltered = rusb::devices().unwrap();
LitraDevices { unfiltered }
}
fn can_not_handle<'r>(dev: &'r rusb::Device<rusb::GlobalContext>) -> bool {
let desc = dev.device_descriptor().unwrap();
match (desc.vendor_id(), desc.product_id()) {
(VENDOR, PRODUCT) => (),
_ => return true,
}
match desc.class_code() {
LIBUSB_CLASS_HID => return true, // Skip HID devices, they are handled directly by OS libraries
_ => return false,
}
}
pub fn iter<'a>(self) -> LitraDeviceIterator<'a> {
let it = self.unfiltered.iter().filter(Self::can_not_handle);
LitraDeviceIterator{
it,
}
}
}
impl <'a> Iterator for LitraDeviceIterator<'a> {
type Item = LitraDevice;
fn next(&mut self) -> Option<Self::Item> {
let n = self.it.next();
match n {
Some(Device) => return Some(LitraDevice{dev: n.unwrap()}),
None => return None,
}
}
}
Now I really cannot figure out how to code LitraDeviceIterator so that it wraps the filtered iterator.
All code iterations I have tried so far turn into a generic nightmare very quickly.
I rewrote your iter() to yield LitraDevice, you can surely take it wherever you wanted to go from there.
The first underlying issue is that filter() yields references, but in cases like these, you actually mean to move yielded items while filtering. That's what filter_map() is capable of. That way, you can scrap the references, greatly simplifying your code.
(This code does not work yet, read on)
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
self.unfiltered.iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}
Now, there's a second little issue at play her: rusb::DeviceList<T : UsbContext>>::iter(&self) returns rusb::Devices<'_, T>, '_ being the anonymous lifetime inferred from &self. Meaning, while you can drive rusb::Devices<'_, T> to yield Device<T>s, you can not actually keep it around longer than self.unfiltered. More specifically, as you consume self in iter(), you can not return an iterator referencing that rusb::Devices<'_, T> from iter(). One solution is to immediately collect, then again moving into an iterator.
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
let devices = self.unfiltered.iter().collect::<Vec<_>>();
devices.into_iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}

How do I make a generic selection of generic functions with same function definition but different T?

In my simplified example I have an algorithm that takes two parameters t: T and transform_fn: fn(&str) -> T where T: TransformRes and trait TransformRes: 'static + Eq + Send {}
Stripped down to a minimum, usage works successfully as below:
struct TransformParameter<T: TransformRes> {
compare: T,
transform_fn: fn(&str) -> T,
}
// TransformParameter works for all types, that implement `Eq`
let t = TransformParameter { compare: transform_usize("5"), transform_fn: transform_usize };
assert_eq!(t.compare, (t.transform_fn)("5"));
let t = TransformParameter { compare: transform_identity("5"), transform_fn: transform_identity };
assert_eq!(t.compare, (t.transform_fn)("5"));
I want to enable a dynamic selection, like so
fn select_transform_fn<T: TransformRes>() -> fn(&str) -> T {
let cond = false;
if cond {
transform_usize
} else {
transform_identity
}
}
This doesn't compile of course and I understand why. Unfortunately, I can't think of a solution that enables me a dynamic selection of the transformation algorithm that preserves me the ability to pass generic functions to my struct TransformParameter.
How can I combine the API that I want with the ability for a dynamic selection of a generic function?
Full code (on Rust Playground):
// Result type of transformation functions.
trait TransformRes: 'static + Eq + Send {}
impl<T> TransformRes for T where T: 'static + Eq + Send {}
struct TransformParameter<T: TransformRes> {
compare: T,
transform_fn: fn(&str) -> T,
}
// Generic Transform Function 1
fn transform_usize(foo: &str) -> usize {
foo.parse::<usize>().unwrap()
}
// Generic Transform Function 2
fn transform_identity(foo: &str) -> String {
String::from(foo)
}
fn main() {
// generic functions: work
let t = TransformParameter { compare: transform_usize("5"), transform_fn: transform_usize };
assert_eq!(t.compare, (t.transform_fn)("5"));
let t = TransformParameter { compare: transform_identity("5"), transform_fn: transform_identity };
assert_eq!(t.compare, (t.transform_fn)("5"));
// generic function selection: doesn't compile.. how to do that?
let foo = select_transform_fn();
foo("foo")
}
fn select_transform_fn<T: TransformRes>() -> fn(&str) -> T {
let cond = false;
if cond {
transform_usize
} else {
transform_identity
}
}

Initialize a Vec with not-None values only

If I have variables like this:
let a: u32 = ...;
let b: Option<u32> = ...;
let c: u32 = ...;
, what is the shortest way to make a vector of those values, so that b is only included if it's Some?
In other words, is there something simpler than this:
let v = match b {
None => vec![a, c],
Some(x) => vec![a, x, c],
};
P.S. I would prefer a solution where we don't need to use the variables more than once. Consider this example:
let some_person: String = ...;
let best_man: Option<String> = ...;
let a_third_person: &str = ...;
let another_opt: Option<String> = ...;
...
As can be seen, we might have to use longer variable names, more than one Option (None), expressions (like a_third_person.to_string()), etc.
Yours is fine, but here's a sophisticated one:
[Some(a), b, Some(c)].into_iter().flatten().collect::<Vec<_>>()
This works since Option impls IntoIterator.
If it depends on just one variable:
b.map(|b| vec![a, b, c]).unwrap_or_else(|| vec![a, c]);
Playground
After some thinking and investigating, I've come with the following crazy thing.
The end goal is to have a macro, optional_vec![], that you can pass it either T or Option<T> and it should behave like described in the question. However, I decided on a strong restriction: it should have the best performance possible. So, you write:
optional_vec![a, b, c]
And get at least the performance of hand-written match, if not more. This forbids the use of the simple [Some(a), b, Some(c)].into_iter().flatten().collect::<Vec<_>>(), suggested in my other answer (though even this solution needs some way to differentiate between Option<T> and just T, which, like we'll see, is not an easy problem at all).
I will first warn that I've not found a way to make my macro work with Option. That is, if you want to build a vector of Option<T> from Option<T> and Option<Option<T>>, it will not work.
When a design a complex macro, I like to think first how the expanded code will look like. And in this macro, we have several hard problems to solve.
First, the macro take plain expressions. But somehow, it needs to switch on their type being T or Option<T>. How should such thing be done?
The feature we use to do such things is specialization.
#![feature(specialization)]
pub trait Optional {
fn some_method(self);
}
impl<T> Optional for T {
default fn some_method(self) {
// Just T
}
}
impl<T> Optional for Option<T> {
fn some_method(self) {
// Option<T>
}
}
Like you probably noticed, now we have two problems: first, specialization is unstable, and I'd like to stay with stable. Second, what should be inside the trait? The second problem is easier to solve, so let's begin with it.
Turns out that the most performant way to do the pushing to the vector is to pre-allocate capacity (Vec::with_capacity), write to the vector by using pointers (don't push(), it optimizes badly!) then set the length (Vec::set_len()).
We can get a pointer to the internal buffer of the vector using Vec::as_mut_ptr(), and advance the pointer via <*mut T>::add(1).
So, we need two methods: one to hint us about the capacity (can be zero for None or one for Some() and non-Option elements), and a write_and_advance() method:
pub trait Optional {
type Item;
fn len(&self) -> usize;
unsafe fn write_and_advance(self, place: &mut *mut Self::Item);
}
impl<T> Optional for T {
default type Item = Self;
default fn len(&self) -> usize { 1 }
default unsafe fn write_and_advance(self, place: &mut *mut Self) {
place.write(self);
*place = place.add(1);
}
}
impl<T> Optional<T> for Option<T> {
type Item = T;
fn len(&self) -> usize { self.is_some() as usize }
unsafe fn write_and_advance(self, place: &mut *mut T) {
if let Some(value) = self {
place.write(value);
*place = place.add(1);
}
}
}
It doesn't even compile! For the why, see Mismatch between associated type and type parameter only when impl is marked `default`. Luckily for us, the trick we'll use to workaround specialization not being stable does work in this situation. But for now, let's assume it works. How will the code using this trait look like?
match (a, b, c) { // The match is here because it's the best binding for liftimes: see https://stackoverflow.com/a/54855986/7884305
(a, b, c) => {
let len = Optional::len(&a) + Optional::len(&b) + Optional::len(&c);
let mut result = ::std::vec::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
Optional::write_and_advance(a, &mut next_element);
Optional::write_and_advance(b, &mut next_element);
Optional::write_and_advance(c, &mut next_element);
result.set_len(len);
}
result
}
}
And it works! Except that it does not, because the specialization does not compile as I said, and we also want to not repeat all of this boilerplate but insert it into a macro.
So, how do we solve the problems with specialization: being unstable and not working?
dtonlay has a very cool trick he calls autoref specialization (BTW, all of this repo is a very recommended reading!). This is a trick that can be used to emulate specialization. It works only in macros, but we're in a macro so this is fine.
I will not elaborate about the trick here (I recommend to read his post; he also used this trick in the excellent and very widely used anyhow crate). In short, the idea is to trick the typechecker by implementing a trait for T under certain conditions (the specialized impl) and other trait for &T for the general case (this could be inherent impl if not coherence). Since Rust performs automatic referencing during method resolution, that is take reference to the receiver as needed, this will work - the typechecker will autoref if needed, and will stop in the first applicable impl - i.e. the specialized impl if it matches, or the general impl otherwise.
Here's an example:
use std::fmt;
pub trait Display {
fn foo(&self);
}
// Level 1
impl<T: fmt::Display> Display for T {
fn foo(&self) { println!("Display({}), {}", std::any::type_name::<T>(), self); }
}
pub trait Debug {
fn foo(&self);
}
// Level 2
impl<T: fmt::Debug> Debug for &T {
fn foo(&self) { println!("Debug({}), {:?}", std::any::type_name::<T>(), self); }
}
macro_rules! foo {
($e:expr) => ((&$e).foo());
}
Playground.
We can use this trick in our case:
#[doc(hidden)]
pub mod autoref_specialization {
#[derive(Copy, Clone)]
pub struct OptionTag;
pub trait OptionKind {
fn optional_kind(&self) -> OptionTag;
}
impl<T> OptionKind for Option<T> {
#[inline(always)]
fn optional_kind(&self) -> OptionTag { OptionTag }
}
impl OptionTag {
#[inline(always)]
pub fn len<T>(self, this: &Option<T>) -> usize { this.is_some() as usize }
#[inline(always)]
pub unsafe fn write_and_advance<T>(self, this: Option<T>, place: &mut *mut T) {
if let Some(value) = this {
place.write(value);
*place = place.add(1);
}
}
}
#[derive(Copy, Clone)]
pub struct DefaultTag;
pub trait DefaultKind {
fn optional_kind(&self) -> DefaultTag;
}
impl<T> DefaultKind for &'_ T {
#[inline(always)]
fn optional_kind(&self) -> DefaultTag { DefaultTag }
}
impl DefaultTag {
#[inline(always)]
pub fn len<T>(self, _this: &T) -> usize { 1 }
#[inline(always)]
pub unsafe fn write_and_advance<T>(self, this: T, place: &mut *mut T) {
place.write(this);
*place = place.add(1);
}
}
}
And the expanded code will look like:
use autoref_specialization::{DefaultKind as _, OptionKind as _};
match (a, b, c) {
(a, b, c) => {
let (a_tag, b_tag, c_tag) = (
(&a).optional_kind(),
(&b).optional_kind(),
(&c).optional_kind(),
);
let len = a_tag.len(&a) + b_tag.len(&b) + c_tag.len(&c);
let mut result = ::std::vec::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
a_tag.write_and_advance(a, &mut next_element);
b_tag.write_and_advance(b, &mut next_element);
c_tag.write_and_advance(c, &mut next_element);
result.set_len(len);
}
result
}
}
It may be tempting to try to convert this immediately into a macro, but we still have one unsolved problem: our macro need to generate identifiers. This may not be obvious, but what if we pass optional_vec![1, Some(2), 3]? We need to generate the bindings for the match (in our case, (a, b, c) => ...) and the tag names ((a_tag, b_tag, c_tag)).
Unfortunately, generating names is not something macro_rules! can do in today's Rust. Fortunately, there is an excellent crate paste (another one from dtonlay!) that is a small proc-macro that allows you to do that. It is even available on the playground!
However, we need a series of identifiers. That can be done with tt-munching, by repeatedly adding some letter (I used a), so you get a, aa, aaa, ... you get the idea.
#[doc(hidden)]
pub mod reexports {
pub use std::vec::Vec;
pub use paste::paste;
}
#[macro_export]
macro_rules! optional_vec {
// Empty case
{ #generate_idents
exprs = []
processed_exprs = [$($e:expr,)*]
match_bindings = [$($binding:ident)*]
tags = [$($tag:ident)*]
} => {{
use $crate::autoref_specialization::{DefaultKind as _, OptionKind as _};
match ($($e,)*) {
($($binding,)*) => {
let ($($tag,)*) = (
$((&$binding).optional_kind(),)*
);
let len = 0 $(+ $tag.len(&$binding))*;
let mut result = $crate::reexports::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
$($tag.write_and_advance($binding, &mut next_element);)*
result.set_len(len);
}
result
}
}
}};
{ #generate_idents
exprs = [$e:expr, $($rest:expr,)*]
processed_exprs = [$($processed_exprs:tt)*]
match_bindings = [$first_binding:ident $($bindings:ident)*]
tags = [$($tags:ident)*]
} => {
$crate::reexports::paste! {
$crate::optional_vec! { #generate_idents
exprs = [$($rest,)*]
processed_exprs = [$($processed_exprs)* $e,]
match_bindings = [
[< $first_binding a >]
$first_binding
$($bindings)*
]
tags = [
[< $first_binding a_tag >]
$($tags)*
]
}
}
};
// Entry
[$e:expr $(, $exprs:expr)* $(,)?] => {
$crate::optional_vec! { #generate_idents
exprs = [$($exprs,)+]
processed_exprs = [$e,]
match_bindings = [__optional_vec_a]
tags = [__optional_vec_a_tag]
}
};
}
Playground.
I can also personally recommend
let mut v = vec![a, c];
v.extend(b);
Short and clear.
Sometime the straight forward solution is the best:
fn jim_power(a: u32, b: Option<u32>, c: u32) -> Vec<u32> {
let mut acc = Vec::with_capacity(3);
acc.push(a);
if let Some(b) = b {
acc.push(b);
}
acc.push(c);
acc
}
fn ys_iii(
some_person: String,
best_man: Option<String>,
a_third_person: String,
another_opt: Option<String>,
) -> Vec<String> {
let mut acc = Vec::with_capacity(4);
acc.push(some_person);
best_man.map(|x| acc.push(x));
acc.push(a_third_person);
another_opt.map(|x| acc.push(x));
acc
}
If you don't care about the order of the values, another option is
Iterator::chain(
[a, c].into_iter(),
[b].into_iter().flatten()
).collect()
Playground

Function that generates a HashMap of Enum variants

I'm working with apollo_parser to parse a GraphQL query. It defines an enum, apollo_parser::ast::Definition, that has several variants including apollo_parser::ast::OperationDefintion and apollo_parser::ast::FragmentDefinition. I'd like to have a single Trait I can apply to apollo_parser::ast::Definition that provides a function definition_map that returns a HashMap mapping the operation name to the variant instance.
I've got as far as the trait, but I don't know how to implement it. Also, I don't know how to constrain T to be a variant of Definition.
trait Mappable {
fn definition_map<T>(&self) -> HashMap<String, T>;
}
EDIT:
Here's a Rust-ish pseudocode implementation.
impl Mappable for Document {
fn definition_map<T>(&self) -> HashMap<String, T> {
let defs = Vec<T> = self.definitions
.filter_map(|def: Definition| match def {
T(foo) => Some(foo),
_ => None
}).collect();
let map = HashMap::new();
for def: T in definitions {
map.insert(def.name(), def);
}
map
}
}
and it would output
// From a document consisting of OperationDefinitions "operation1" and "operation2"
// and FragmentDefinitons "fragment1" and "fragment2"
{
"operation1": OperationDefinition(...),
"operation2": OperationDefinition(...),
}
{
"fragment1": FragmentDefinition(...),
"fragment2": FragmentDefinition(...)
}
I don't know how to constrain T to be a variant of Definition.
There is no such thing in Rust. There's the name of the variant and the name of the type contained within that variant, there is no relationship between the two. The variants can be named whatever they want, and multiple variant can contain the same type. So there's no shorthand for pulling a T out of an enum which has a variant with a T.
You need to make your own trait that says how to get a T from a Definition:
trait TryFromDefinition {
fn try_from_def(definition: Definition) -> Option<Self> where Self: Sized;
fn name(&self) -> String;
}
And using that, your implementation is simple:
impl Mappable for Document {
fn definition_map<T: TryFromDefinition>(&self) -> HashMap<String, T> {
self.definitions()
.filter_map(T::try_from_def)
.map(|t| (t.name(), t))
.collect()
}
}
You just have to define TryFromDefinition for all the types you want to use:
impl TryFromDefinition for OperationDefinition {
fn try_from_def(definition: Definition) -> Option<Self> {
match definition {
Definition::OperationDefinition(operation) => Some(operation),
_ => None,
}
}
fn name(&self) -> String {
self.name().unwrap().ident_token().unwrap().text().into()
}
}
impl TryFromDefinition for FragmentDefinition {
fn try_from_def(definition: Definition) -> Option<Self> {
match definition {
Definition::FragmentDefinition(operation) => Some(operation),
_ => None,
}
}
fn name(&self) -> String {
self.fragment_name().unwrap().name().unwrap().ident_token().unwrap().text().into()
}
}
...
Some of this could probably be condensed using macros, but there's no normalized way that I can tell to get a name from a definition, so that would still have to be custom per type.
You should also decide how you want to handle definitions that don't have a name; you'd probably want to return Option<String> to avoid all those .unwrap()s, but I don't know how you'd want to put that in your HashMap.
Without knowing your whole workflow, I might suggest a different route instead:
struct Definitions {
operations: HashMap<String, OperationDefinition>,
fragments: HashMap<String, FragmentDefinition>,
...
}
impl Definitions {
fn from_document(document: &Document) -> Self {
let mut operations = HashMap::new();
let mut fragments = HashMap::new();
...
for definition in document.definitions() {
match definition {
Definition::OperationDefinition(operation) => {
let name: String = operation.name().unwrap().ident_token().unwrap().text().into();
operations.insert(name, operation);
},
Definition::FragmentDefinition(fragment) => {
let name: String = fragment.fragment_name().unwrap().name().unwrap().ident_token().unwrap().text().into();
fragments.insert(name, fragment);
},
...
}
}
Definitions {
operations,
fragments,
...
}
}
}

How do I collect from multiple iterator types?

I am attempting to implement a new trait for a String that has a function that capitalizes the first letter of each String and un-capitalizes the rest. I am basing the function's interface on to_uppercase() and to_lowercase() in the Rust Standard Library.
use std::io;
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
self.chars().enumerate().map(|(i, c)| {
match i {
0 => c.to_uppercase(),
_ => c.to_lowercase(),
}
}).collect()
}
}
fn main() {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).ok().expect("Unable to read from stdin.");
println!("{}", buffer.to_capitalized());
}
This code is based on a suggestion given here, but the code is outdated and causes multiple compilation errors. The only issue I am having with my implementation now is the following error:
src/main.rs:10:13: 13:14 error: match arms have incompatible types [E0308]
src/main.rs:10 match i {
^
src/main.rs:10:13: 13:14 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:10:13: 13:14 note: expected type `std::char::ToUppercase`
src/main.rs:10:13: 13:14 note: found type `std::char::ToLowercase`
src/main.rs:12:22: 12:38 note: match arm with an incompatible type
src/main.rs:12 _ => c.to_lowercase(),
So in short, the return values of fn to_uppercase(&self) -> ToUppercase and fn to_lowercase(&self) -> ToLowercase can't be collected together because the map now has multiple return types.
I've attempted trying to cast them to another common Iterator type such as Bytes and Chars, but these iterator types can't be collected to form a String. Any suggestions?
Casting is rarely a good approach to solving type issues in Rust. The correct solution here would be to write (or find a crate that defines) a type that unifies disparate iterator types. But that would require effort, so it's simpler to just throw collect out the window:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
let mut r = String::with_capacity(self.len());
for (i, c) in self.chars().enumerate() {
match i {
0 => r.extend(c.to_uppercase()),
_ => r.extend(c.to_lowercase()),
}
}
r
}
}
fn main() {
let buffer = String::from("canberra");
println!("{}", buffer.to_capitalized());
}
This is, more or less, what collect would do anyway if you had some type to represent "either ToUppercase or ToLowercase". In the vast majority of cases, this will also only perform a single allocation.
Here's how I would do it:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
match self.chars().next() {
Some(c) => {
c.to_uppercase()
.chain(self.chars().skip(1).flat_map(|c| c.to_lowercase()))
.collect()
}
None => String::new(),
}
}
}
fn main() {
println!("{}", "fOoBaR".to_string().to_capitalized());
}
This will be a little slower than the ideal solution, as it decodes the first char twice, but it's quite readable IMO.
Output:
Foobar
After looking at the implementation for pub fn to_uppercase(&self) -> String here, I devised a solution that is a bit of a hybrid between Dogbert and DK.'s solutions and the implementation given in the standard library. It even works with Unicode!
fn to_capitalized(&self) -> String {
match self.len() {
0 => String::new(),
_ => {
let mut s = String::with_capacity(self.len());
s.extend(self.chars().next().unwrap().to_uppercase());
s.extend(self.chars().skip(1).flat_map(|c| c.to_lowercase()));
return s;
}
}
}
Working Rust Playground Example
Edit: For greater visibility, Shepmaster's simplified and optimized solution:
fn to_capitalized(&self) -> String {
let mut s = String::with_capacity(self.len());
let mut chars = self.chars();
s.extend(chars.by_ref().take(1).flat_map(|c| c.to_uppercase()));
s.extend(chars.flat_map(|c| c.to_lowercase()));
s
}

Resources