You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rsh/src/ext/mod.rs

98 lines
3.1 KiB

//! Extensions
use super::*;
use std::mem::{self, MaybeUninit};
use std::iter;
use smallvec::SmallVec;
mod alloc;
pub use alloc::*;
mod hex;
pub use hex::*;
mod base64;
pub use self::base64::*;
/// A maybe-atom that can spill into a vector.
pub type MaybeVec<T> = SmallVec<[T; 1]>;
/// Allocate a vector of `MaybeUninit<T>`.
pub fn vec_uninit<T>(sz: usize) -> Vec<MaybeUninit<T>>
{
let mut mem: Vec<T> = Vec::with_capacity(sz);
unsafe {
mem.set_len(sz);
mem::transmute(mem)
}
}
/// Create a blanket-implementing trait that is a subtrait of any number of traits.
///
/// # Usage
/// To subtype a trait with `Sized` types only:
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub SizedUnpinAsyncRead; "This subtrait must be sized": std::marker::Unpin + tokio::io::AsyncRead);
/// ```
/// To impl the trait for unsized types as well:
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub dyn UnsizedUnpinAsyncRead; "Subtraits `Unpin` and `AsyncRead`. Also implemented for unsized types.": std::marker::Unpin + tokio::io::AsyncRead);
/// ```
/// # Downcastable subtrait
/// To create a subtrait that can be downcasted (correctly coerces to `dyn Any`), use the `virtual` keyword.
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub virtual DowncastableUnpinAsyncRead; "Subtraits `Unpin` and `AsyncRead`. Also dynamically downcastable": std::marker::Unpin + tokio::io::AsyncRead);
/// subtrait!(pub virtual AnotherAny; "A dynamically downcastable trait that subtraits nothing else but `Any`");
/// ```
#[macro_export] macro_rules! subtrait {
(@ $v:vis $name:ident $(; $doc:literal)?: $($t:path),+) => {
$(#[doc = $doc])?
$v trait $name: $($t+)+ {}
};
($v:vis $name:ident $(; $doc:literal)?: $($t:path),+) => {
$crate::subtrait!(@ $v $name $(; $doc)?: Sized, $($t),+);
impl<T: $($t+)+> $name for T{}
};
($v:vis dyn $name:ident $(; $doc:literal)?: $($t:path),+) => {
$crate::subtrait!(@ $v $name $(; $doc)?: $($t),+);
impl<T: ?Sized + $($t+)+> $name for T{}
};
($v:vis virtual $name:ident $(; $doc:literal)?$(: $($t:path),*)?) => {
$crate::subtrait!(@ $v $name $(; $doc)?: ::mopa::Any $(, $($t),*)?);
const _:() = {
fn _assert_object_safe(_: &dyn $name){}
};
mopafy!($name);
impl<T: ?Sized + ::mopa::Any $(+ $($t+)+)?> $name for T {}
};
}
// Static testing of `subtrait`
const _:() = {
use mopa::*;
subtrait!(dyn Test; "test dynamic subtrait": std::marker::Unpin);
subtrait!(virtual TestAny; "test downcastable subtrait of `Read` and `Write`": std::io::Read);
subtrait!(virtual TestAny2; "test downcastable subtrait of only `Any`");
const fn _a<T: Test+?Sized>(){}
const fn _b<T: TestAny+?Sized>(){}
fn _c(a: Box<dyn TestAny>)
{
if a.is::<std::io::Stdin>() {
let _ref: &std::io::Stdin = a.downcast_ref::<std::io::Stdin>().unwrap();
drop(_ref);
let _unbox: std::io::Stdin = *a.downcast().map_err(|_| ()).unwrap();
}
}
fn _d(a: &dyn TestAny)
{
if a.is::<std::io::Stdin>() {
let _ref: &std::io::Stdin = a.downcast_ref::<std::io::Stdin>().unwrap();
}
}
const _TEST: () = _a::<dyn Test>();
const _TEST2: () = _b::<dyn TestAny>();
};