I am trying to reduce the boilerplate in my code. I have tried to use Cow, Borrow or AsRef to combine these implementations together, but the compiler complains that Address does not implement the trait sized.
To implement all the cases &str vs String and Address vs &Address, my current code feels excessive
pub struct Address(String);
impl From<String> for Address {
fn from(bytes: String) -> Self {
Self(String::from_utf8(Vec::from(bytes)).unwrap())
}
}
impl From<String> for &Address {
fn from(bytes: String) -> Self {
&Address(String::from_utf8(Vec::from(bytes)).unwrap())
}
}
impl From<&str> for Address {
fn from(str: &str) -> Self {
Self(str.to_string())
}
}
impl From<&str> for &Address {
fn from(str: &str) -> Self {
&Address(str.to_string())
}
}
impl<'b> Into<&'b str> for Address {
fn into(self) -> &'b str {
self.0.as_str()
}
}
impl<'b> Into<&'b str> for &Address {
fn into(self) -> &'b str {
self.0.as_str()
}
}
impl<'b> Into<String> for Address {
fn into(self) -> String {
self.0.to_string()
}
}
impl<'b> Into<String> for &Address {
fn into(self) -> String {
self.0.to_string()
}
}
You should probably only have the following four impls:
pub struct Address(String);
impl From<String> for Address {
fn from(s: String) -> Self {
Self(s)
}
}
impl<'a> From<&'a str> for Address {
fn from(s: &'a str) -> Self {
Address(s.to_string())
}
}
impl From<Address> for String {
fn from(a: Address) -> Self {
a.0
}
}
impl<'a> From<&'a Address> for &'a str {
fn from(a: &'a Address) -> Self {
&a.0
}
}
String::from_utf8(Vec::from(bytes)).unwrap() makes no sense. bytes in your case is already a UTF8 String, so this entire line is redundant. Did you mean bytes to be Vec<u8>?
impl From<X> for &Address makes no sense. References don't own an object, and someone has to own the Address object. impl From<X> for Address is what you really want and already have.
impl Into<&str> makes no sense, Into takes ownership. You can't consume an object and then return a reference to it. Again, someone has to own it. You probably want AsRef<str> and Deref<Target=str>.
impl Into<String> for &Address is also unusual. AsRef<str> and Deref<Target=str> is sufficient for almost all cases, and if you want a consuming conversion, use impl From<Address> for String. Never implement Into, always implement From instead. (From implies Into)
So this is what I would do:
use std::ops::Deref;
pub struct Address(String);
impl From<String> for Address {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&str> for Address {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl AsRef<str> for Address {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Deref for Address {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
// Unusual, but of course possible:
impl From<Address> for String {
fn from(addr: Address) -> String {
addr.0
}
}
This is how to perform the conversions then, which is in line with usual Rust behaviour:
fn main() {
// String to Address
let s: String = "AAA".to_string();
let _addr: Address = s.into();
//or
let s: String = "AAA".to_string();
let _addr = Address::from(s);
// &str to Address
let s: &str = "AAA";
let _addr: Address = s.into();
// or
let _addr = Address::from(s);
// Address to &str
let addr: Address = Address("AAA".to_string());
let _s: &str = &addr;
// Address to String
let addr: Address = Address("AAA".to_string());
let _s: String = addr.to_string();
// Or also:
let _s: String = addr.into();
}
Related
I have a container where I can store items implementing the CommonBase trait and I have some other traits (TypeA and TypeB for example, but there can be unknown number of other TypeX traits) with the CommonBase as their super trait. I store objects implementing ItemA to container and I can get a reference to item back from the container, but as reference to the CommonBase.
I want to cast the item back to its original type like this:
fn cast_to<T: SuperTrait>(val: dyn CommonBase) -> Result<T, dyn Error> {...}
Can anyone help please?
Here is my experimental code
use std::error::Error;
use std::rc::Rc;
pub trait CommonBase {
fn to_common(self: &Self);
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) { todo!() }
}
impl TypeA for StructA {
fn do_a(self: &Self) { todo!() }
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) { todo!() }
}
impl TypeB for StructB {
fn do_b(self: &Self) { todo!() }
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(self: &mut Self, item: Rc<dyn CommonBase>) {
self.items.push(item);
}
pub fn get(self, idx: usize) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(val: Rc<dyn CommonBase>) -> Result<Rc<dyn T>, Box<dyn Error>> {...} // <- some magic is done here
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get_common(0); // actually TypeA
let stored_a: Rc<dyn TypeA> = cast_to(stored_a_as_common).unwrap();
stored_a.do_a();
}
Here is your code with a few additions.
For this, you need std::any::Any.
Each struct subject to dynamic cast should be known as dyn Any in order to try the dynamic cast; this is the purpose of .as_any() and .as_any_mut() in the example.
Using .downcast_ref() or .downcast_mut() requires you target a type, not a trait.
I don't think you can have at the same time two Rcs pointing towards the same struct but declared with different dyn traits.
The best to do, in my opinion, is to only deal with references (wherever they come from, Rc or something else).
You expected an Error when the dynamic cast is impossible, then I wrote the function this way.
Note however that .downcast_ref() returns an Option and this is generally good enough (None means that the cast is impossible); we could simplify the code with just this line val.as_any().downcast_ref::<T>().
use std::error::Error;
use std::rc::Rc;
use std::any::Any;
pub trait CommonBase: Any {
fn to_common(self: &Self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub trait TypeA: CommonBase {
fn do_a(self: &Self);
}
pub trait TypeB: CommonBase {
fn do_b(self: &Self);
}
pub struct StructA {}
impl CommonBase for StructA {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeA for StructA {
fn do_a(self: &Self) {
println!("doing a");
}
}
pub struct StructB {}
impl CommonBase for StructB {
fn to_common(self: &Self) {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TypeB for StructB {
fn do_b(self: &Self) {
println!("doing b");
}
}
pub struct Container {
items: Vec<Rc<dyn CommonBase>>,
}
impl Container {
pub fn new() -> Container {
Container { items: Vec::new() }
}
pub fn add(
self: &mut Self,
item: Rc<dyn CommonBase>,
) {
self.items.push(item);
}
pub fn get(
&self,
idx: usize,
) -> Rc<dyn CommonBase> {
self.items.get(idx).unwrap().clone()
}
}
fn cast_to<T: CommonBase>(
val: &dyn CommonBase
) -> Result<&T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any().downcast_ref::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
#[allow(dead_code)] // unused in this example
fn cast_to_mut<T: CommonBase>(
val: &mut dyn CommonBase
) -> Result<&mut T, Box<dyn Error>> {
if let Some(t_ref) = val.as_any_mut().downcast_mut::<T>() {
Ok(t_ref)
} else {
Err("bad cast")?
}
}
fn main() {
let mut container = Container::new();
let item_a = Rc::new(StructA {});
let item_b = Rc::new(StructB {});
container.add(item_a); // index 0
container.add(item_b); // index 1
let stored_a_as_common: Rc<dyn CommonBase> = container.get(0); // actually TypeA
let stored_a: &dyn TypeA =
cast_to::<StructA>(stored_a_as_common.as_ref()).unwrap();
stored_a.do_a();
let stored_b_as_common: Rc<dyn CommonBase> = container.get(1); // actually TypeB
let stored_b: &dyn TypeB =
cast_to::<StructB>(stored_b_as_common.as_ref()).unwrap();
stored_b.do_b();
}
/*
doing a
doing b
*/
Im a bit confused by self. Could you please help me along?? Im trying to append or push a new value into the vec. This only shows me that I have no idea what self actually is. The error I'm getting is :
---- ^^^^ this call modifies `self` in-place
| |
| you probably want to use this value after calling the method...
= note: ...instead of the `()` output of method `push`
Why does the following work but...
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
fn append_bar(self) -> Self{
self.to_string() + "Bar"
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
this do not?
trait AppendBar<T> {
fn append_bar(self) -> Self;
}
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
Because self is a Vec<String> and you can't push a Vec<String> into a Vec<String> (which the error message tells you: "Expected String got Vec<String>").
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
Because Vec::append doesn't return anything, so you need to return self yourself (or take &mut self as parameter and return nothing).
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
Because "Bar".to_string() is not guaranteed to be a T for all types T.
My question is about dereferencing and referencing in rust.
I have the following code:
#[database("pg_db")]
struct PgDbConn(diesel::PgConnection);
fn main() {
rocket::ignite()
.attach(PgDbConn::fairing())
.mount("/", routes![find_one, find_all])
.launch();
}
#[get("/<id>", format = "json")]
fn find_one(conn: PgDbConn, id: i32) -> Result<Json<Person>, NotFound<String>> {
let one: QueryResult<Person> = person.find(id).first(&*conn); // Notice here deref & ref
...
I would like to know how my PgDbConn struct ends up as a connection. Can someone please explain the mechanism in detail?
Let's have a look at (part of) the implementation of the database attribute macro:
Ok(quote! {
//...
impl ::std::ops::Deref for #guard_type {
type Target = #conn_type;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::std::ops::DerefMut for #guard_type {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
})
#guard_type is PgDbConn and #conn_type is diesel::PgConnection in your example, so the produced code looks like this:
impl ::std::ops::Deref for PgDbConn {
type Target = diesel::PgConnection;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::std::ops::DerefMut for PgDbConn {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
With Deref and DerefMut, you can implement dereference for your own types, in this case PgDbConn. Now, you can write *conn to get a diesel::PgConnection from your PgDbConn. However, you want a reference to diesel::PgConnection. To get a reference, you have to again reference the dereferenced PgDbConn, so the end result is &*conn.
I'd like to use Factory to build an object from the String and have multiple impls: 1) actual building and 2) caching (stores in-memory in HashMap). The problem is that in case #1 it have to pass the ownership and in case #2 HashMap owns the value and a reference can be returned only.
use std::collections::HashMap;
// product interface
pub trait TProduct {
fn get_title(&self) -> &String;
}
// and concrete impls
pub struct ConcreteProduct1 {
}
impl TProduct for ConcreteProduct1 {
// ...
}
pub struct ConcreteProduct2 {
}
impl TProduct for ConcreteProduct2 {
// ...
}
// factory interface
pub trait TProductFactory {
fn product_from_text(&mut self, text: String) -> Box<dyn TProduct>;
// QUESTION: should it be Box (required for ProductFactory) or &Box (required for ProductCachingProxy)?
}
// actual building factory
pub struct ProductFactory {
}
impl TProductFactory for ProductFactory {
fn product_from_text(&mut self, text: String) -> Box<dyn TProduct> {
//...
// depending on some conditions
Box::new(ConcreteProduct1::from_text(text)); // has to pass the ownership
// or
Box::new(ConcreteProduct2::from_text(text)); // has to pass the ownership
//...
}
}
// caching proxy
trait TProductCache {
fn put(&mut self, text: &String, product: Box<dyn TProduct>);
fn get(&self, text: &String) -> Option<&Box<dyn TProduct>>;
fn clear(&mut self);
}
struct InMemoryProductCache {
map: HashMap<String, Box<dyn TProduct>>
}
impl InMemoryProductCache {
fn new() -> Self {
return InMemoryProductCache {
map: HashMap::new()
}
}
}
impl TProductCache for InMemoryProductCache {
fn put(&mut self, text: &String, product: Box<dyn TProduct>) {
self.map.insert(text.to_string(), product);
}
fn get(&self, text: &String) -> Option<&Box<dyn TProduct>> {
return match self.map.get(text) {
Some(boxed_product) => Some(boxed_product), // have to pass a reference to let it still own the value
None => None
}
}
fn clear(&mut self) {
self.map.clear();
}
}
struct ProductCachingProxy {
product_factory: Box<dyn TProductFactory>,
cache: Box<dyn TProductCache>
}
impl ProductCachingProxy {
fn new_for_factory(product_factory: Box<dyn TProductFactory>, cache: Box<dyn TProductCache>) -> Self {
return ProductCachingProxy {
product_factory,
cache
}
}
}
impl TProductFactory for ProductCachingProxy {
fn product_from_text(&mut self, text: String) -> &Box<dyn TProduct> { // can't pass ownership
let boxed_product = match self.cache.get(&text) {
Some(found_boxed_product) => found_boxed_product,
_ => {
// delegate creation to wrapped TProductFactory impl (`product_factory`)
let boxed_product = self.product_factory.product_from_text(text.clone());
// ... and put to the cache
self.cache.put(&text, boxed_product);
&boxed_product
}
};
return boxed_product;
}
}
// QUESTION: should it be Box (required for ProductFactory) or &Box (required for ProductCachingProxy) to be returned from TProductFactory.fn product_from_text(&mut self, text: String) -> Box<dyn TProduct>; ?
If caching proxy to return a Box, how can it be created from a reference without copying/cloning (TProductCache.get(..))?
Replace Box with Rc (or Arc if you use threads). It provides shared ownership and suites both your cases with single signature. Another option is to use Cow that is a enum of owned and borrowed states.
The following code does not compile:
use std::str::Chars;
struct Chunks {
remaining: Chars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars(),
}
}
}
The error is:
error[E0106]: missing lifetime specifier
--> src/main.rs:4:16
|
4 | remaining: Chars,
| ^^^^^ expected lifetime parameter
Chars doesn't own the characters it iterates over and it can't outlive the &str or String it was created from.
Is there an owned version of Chars that does not need a lifetime parameter or do I have to keep a Vec<char> and an index myself?
std::vec::IntoIter is an owned version of every iterator, in a sense.
use std::vec::IntoIter;
struct Chunks {
remaining: IntoIter<char>,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars().collect::<Vec<_>>().into_iter(),
}
}
}
Playground link
Downside is additional allocation and a space overhead, but I am not aware of the iterator for your specific case.
Ouroboros
You can use the ouroboros crate to create a self-referential struct containing the String and a Chars iterator:
use ouroboros::self_referencing; // 0.4.1
use std::str::Chars;
#[self_referencing]
pub struct IntoChars {
string: String,
#[borrows(string)]
chars: Chars<'this>,
}
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.with_mut(|me| me.chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.with(|me| me.chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoCharsBuilder {
string: self,
chars_builder: |s| s.chars(),
}
.build()
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
Rental
You can use the rental crate to create a self-referential struct containing the String and a Chars iterator:
#[macro_use]
extern crate rental;
rental! {
mod into_chars {
pub use std::str::Chars;
#[rental]
pub struct IntoChars {
string: String,
chars: Chars<'string>,
}
}
}
use into_chars::IntoChars;
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.rent_mut(|chars| chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.rent(|chars| chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoChars::new(self, |s| s.chars())
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
There's also the owned-chars crate, which
provides an extension trait for String with two methods, into_chars and into_char_indices. These methods parallel String::chars and String::char_indices, but the iterators they create consume the String instead of borrowing it.
You could implement your own iterator, or wrap Chars like this (with just one small unsafe block):
// deriving Clone would be buggy. With Rc<>/Arc<> instead of Box<> it would work though.
struct OwnedChars {
// struct fields are dropped in order they are declared,
// see https://stackoverflow.com/a/41056727/1478356
// with `Chars` it probably doesn't matter, but for good style `inner`
// should be dropped before `storage`.
// 'static lifetime must not "escape" lifetime of the struct
inner: ::std::str::Chars<'static>,
// we need to box anyway to be sure the inner reference doesn't move when
// moving the storage, so we can erase the type as well.
// struct OwnedChar<S: AsRef<str>> { ..., storage: Box<S> } should work too
storage: Box<AsRef<str>>,
}
impl OwnedChars {
pub fn new<S: AsRef<str>+'static>(s: S) -> Self {
let storage = Box::new(s) as Box<AsRef<str>>;
let raw_ptr : *const str = storage.as_ref().as_ref();
let ptr : &'static str = unsafe { &*raw_ptr };
OwnedChars{
storage: storage,
inner: ptr.chars(),
}
}
pub fn as_str(&self) -> &str {
self.inner.as_str()
}
}
impl Iterator for OwnedChars {
// just `char` of course
type Item = <::std::str::Chars<'static> as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl DoubleEndedIterator for OwnedChars {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
impl Clone for OwnedChars {
fn clone(&self) -> Self {
// need a new allocation anyway, so simply go for String, and just
// clone the remaining string
OwnedChars::new(String::from(self.inner.as_str()))
}
}
impl ::std::fmt::Debug for OwnedChars {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let storage : &str = self.storage.as_ref().as_ref();
f.debug_struct("OwnedChars")
.field("storage", &storage)
.field("inner", &self.inner)
.finish()
}
}
// easy access
trait StringExt {
fn owned_chars(self) -> OwnedChars;
}
impl<S: AsRef<str>+'static> StringExt for S {
fn owned_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
See playground
As copied from How can I store a Chars iterator in the same struct as the String it is iterating on?:
use std::mem;
use std::str::Chars;
/// I believe this struct to be safe because the String is
/// heap-allocated (stable address) and will never be modified
/// (stable address). `chars` will not outlive the struct, so
/// lying about the lifetime should be fine.
///
/// TODO: What about during destruction?
/// `Chars` shouldn't have a destructor...
struct OwningChars {
_s: String,
chars: Chars<'static>,
}
impl OwningChars {
fn new(s: String) -> Self {
let chars = unsafe { mem::transmute(s.chars()) };
OwningChars { _s: s, chars }
}
}
impl Iterator for OwningChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next()
}
}
Here is a solution without unsafe.
It provides the same effect as s.chars().collect::<Vec<_>>().into_iter(), but without the allocation overhead.
struct OwnedChars {
s: String,
index: usize,
}
impl OwnedChars {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
Together with a little bit of trait magic:
trait StringExt {
fn into_chars(self) -> OwnedChars;
}
impl StringExt for String {
fn into_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
You can do:
struct Chunks {
remaining: OwnedChars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.into_chars(),
}
}
}