Skip to content

Instantly share code, notes, and snippets.

@webern
Created July 20, 2020 02:20
Show Gist options
  • Save webern/3003f10e64564577dc1d83483b49f342 to your computer and use it in GitHub Desktop.
Save webern/3003f10e64564577dc1d83483b49f342 to your computer and use it in GitHub Desktop.
Generalizing a Struct that holds a Cow
#![forbid(missing_debug_implementations, missing_copy_implementations)]
#![deny(rust_2018_idioms)]
#![deny(clippy::pedantic)]
#![allow(dead_code)]
use std::borrow::Cow;
use std::fmt::Debug;
/// A custom type. Clone is required by `Cow`. `Debug` is required by our example so that we can
/// easily print our results. `Copy` is added for completeness since `MyType` has no allocations.
#[derive(Debug, Clone, Copy)]
pub struct MyType {
pub myval: u64,
}
/// In order for this to work, we need `MyType` to easily convert into an owned `Cow`.
impl<'a> Into<Cow<'a, MyType>> for MyType {
fn into(self) -> Cow<'a, MyType> {
Cow::Owned(self)
}
}
/// In order for this to work, we need `&MyType` to easily convert into a borrowed `Cow`.
impl<'a> Into<Cow<'a, MyType>> for &'a MyType {
fn into(self) -> Cow<'a, MyType> {
Cow::Borrowed(self)
}
}
/// A struct that lets the user decide whether the struct should take ownership of `T` data or hold
/// a reference.
struct YouDecide<'a, T: Debug + Clone> {
s: Cow<'a, T>,
}
impl<'a, T: Debug + Clone> YouDecide<'a, T> {
/// Create a new struct from any type `U`, where U can be converted into `Cow<T>`. That is, we
/// allow the user to pass in either a reference or a moved/owned object, and the struct will
/// hold either the reference or the ownership.
fn new<U>(value: U) -> Self
where
U: Into<Cow<'a, T>>,
{
Self { s: value.into() }
}
/// Return a reference to the underlying data.
fn value(&self) -> &T {
self.s.as_ref()
}
}
fn main() {
// create some objects and references of a custom type.
let x = MyType { myval: 1 };
let y = &x;
let z = MyType { myval: 2 };
// create some YouDecide objects from the above objects and references.
let a = YouDecide::new(x);
let b = YouDecide::new(y);
let c = YouDecide::new(z);
// print the values held by the YouDecide objects
println!("{:?}", a.value());
println!("{:?}", b.value());
println!("{:?}", c.value());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment