use std::hash::Hash;
use std::ops::Deref;
use better_any::{Tid, TidAble};
use quote::ToTokens;
#[derive(Debug, Tid)]
pub enum MaybeBorrowed<'a, T> {
Borrowed(&'a T),
Owned(T),
}
impl<'a, T> ToTokens for MaybeBorrowed<'a, T>
where
T: ToTokens,
{
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
(**self).to_tokens(tokens);
}
fn to_token_stream(&self) -> proc_macro2::TokenStream {
(**self).to_token_stream()
}
fn into_token_stream(self) -> proc_macro2::TokenStream
where
Self: Sized,
{
self.to_token_stream()
}
}
impl<'a, T> PartialEq for MaybeBorrowed<'a, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&**self, &**other)
}
}
impl<'a, T> Eq for MaybeBorrowed<'a, T> where T: Eq {}
impl<'a, T> PartialOrd for MaybeBorrowed<'a, T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<'a, T> Ord for MaybeBorrowed<'a, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
Ord::cmp(&**self, &**other)
}
}
impl<'a, T> MaybeBorrowed<'a, T> {
pub const fn is_borrowed(&self) -> bool {
match self {
Self::Borrowed(_) => true,
Self::Owned(_) => false,
}
}
pub const fn is_owned(&self) -> bool {
!self.is_borrowed()
}
}
impl<'a, T> Hash for MaybeBorrowed<'a, T>
where
T: Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<'a, T> Deref for MaybeBorrowed<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
MaybeBorrowed::Borrowed(val) => val,
MaybeBorrowed::Owned(ref val) => val,
}
}
}
impl<'a, T> From<T> for MaybeBorrowed<'a, T> {
fn from(value: T) -> Self {
Self::Owned(value)
}
}
impl<'a, T> From<&'a T> for MaybeBorrowed<'a, T> {
fn from(value: &'a T) -> Self {
Self::Borrowed(value)
}
}
#[allow(clippy::module_name_repetitions)]
pub trait FromMaybeBorrowed<'a, T: 'a> {
fn from_maybe_borrowed(from: MaybeBorrowed<'a, T>) -> Self;
fn from_owned(from: T) -> Self
where
Self: Sized,
{
Self::from_maybe_borrowed(from.into())
}
fn from_borrowed(from: &'a T) -> Self
where
Self: Sized,
{
Self::from_maybe_borrowed(from.into())
}
}
#[cfg(test)]
mod test {
use super::MaybeBorrowed;
#[test]
fn is_borrowed() {
let test_data = String::from("Test Data");
let maybe_borrowed: MaybeBorrowed<String> = (&test_data).into();
assert!(maybe_borrowed.is_borrowed());
assert!(!maybe_borrowed.is_owned());
}
#[test]
fn is_owned() {
let test_data = String::from("Test Data");
let maybe_borrowed: MaybeBorrowed<String> = test_data.into();
assert!(!maybe_borrowed.is_borrowed());
assert!(maybe_borrowed.is_owned());
}
#[test]
fn from_reference() {
let test_data = String::from("Test Data");
let maybe_borrowed: MaybeBorrowed<String> = (&test_data).into();
assert_eq!(maybe_borrowed, MaybeBorrowed::Borrowed(&test_data));
}
#[test]
fn from_owned() {
let test_data = String::from("Test Data");
let maybe_borrowed: MaybeBorrowed<String> = test_data.clone().into();
assert_eq!(maybe_borrowed, MaybeBorrowed::Owned(test_data));
}
}