Implement the foundations for annotation generation
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
__internal::{display, type_id},
|
||||
Cdef, CdefBuilder, FfiReturnConvention, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder,
|
||||
TypeType, UnsafeExternCFn,
|
||||
Cdef, CdefBuilder, ExternCFn, FfiReturnConvention, IntoFfi, Metatype, MetatypeBuilder, Type,
|
||||
TypeBuilder, TypeType,
|
||||
};
|
||||
use luaify::luaify;
|
||||
use std::{
|
||||
@@ -152,8 +152,8 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
|
||||
unsafe impl<F: Future<Output: IntoFfi> + 'static> Cdef for lua_future<F> {
|
||||
fn build(s: &mut CdefBuilder) {
|
||||
s.field_opaque(mem::offset_of!(Self, take)) // opaque .sig, .poll and .state
|
||||
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::Into>>("__take")
|
||||
.field::<UnsafeExternCFn<(&mut Self,), ()>>("__drop");
|
||||
.field::<ExternCFn<(&mut Self,), <F::Output as IntoFfi>::Into>>("__take")
|
||||
.field::<ExternCFn<(&mut Self,), ()>>("__drop");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,24 +6,6 @@ use std::{
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub mod stub_types {
|
||||
pub struct any;
|
||||
pub struct many;
|
||||
pub struct nil;
|
||||
pub type boolean = bool;
|
||||
pub struct lightuserdata;
|
||||
pub struct number;
|
||||
pub struct integer;
|
||||
pub type string = String;
|
||||
pub struct table;
|
||||
pub struct function;
|
||||
pub struct userdata;
|
||||
pub struct thread;
|
||||
pub struct cdata;
|
||||
pub struct variadic;
|
||||
}
|
||||
|
||||
pub fn type_id<T: 'static>() -> u64 {
|
||||
let mut hash = FxHasher::default();
|
||||
TypeId::of::<T>().hash(&mut hash);
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::{
|
||||
#[path = "./internal.rs"]
|
||||
pub mod __internal;
|
||||
pub mod future;
|
||||
pub mod marker;
|
||||
pub mod option;
|
||||
pub mod result;
|
||||
pub mod string;
|
||||
@@ -136,9 +137,9 @@ pub struct Registry {
|
||||
impl Registry {
|
||||
pub fn new() -> Self {
|
||||
let mut s = Self::default();
|
||||
s.declare::<UnsafeExternCFn<(*const c_void,), ()>>(KEEP_FN);
|
||||
s.declare::<UnsafeExternCFn<(*const u8, usize), bool>>(IS_UTF8_FN);
|
||||
s.declare::<UnsafeExternCFn<(*mut lua_buffer,), ()>>(DROP_BUFFER_FN);
|
||||
s.declare::<ExternCFn<(*const c_void,), ()>>(KEEP_FN);
|
||||
s.declare::<ExternCFn<(*const u8, usize), bool>>(IS_UTF8_FN);
|
||||
s.declare::<ExternCFn<(*mut lua_buffer,), ()>>(DROP_BUFFER_FN);
|
||||
s
|
||||
}
|
||||
|
||||
@@ -603,6 +604,10 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Annotation {
|
||||
fn annotation() -> impl Display;
|
||||
}
|
||||
|
||||
//
|
||||
// SAFETY: Unit type return maps to a C void return, which is a nil return in lua. There is no
|
||||
// equivalent to passing a unit type as an argument in C.
|
||||
@@ -636,7 +641,7 @@ impl_void!(());
|
||||
impl_void!(c_void);
|
||||
|
||||
macro_rules! impl_primitive {
|
||||
($rty:ty, $cty:expr) => {
|
||||
($rty:ty, $cty:expr, $lty:expr) => {
|
||||
unsafe impl Type for $rty {
|
||||
fn name() -> impl Display {
|
||||
$cty
|
||||
@@ -652,22 +657,28 @@ macro_rules! impl_primitive {
|
||||
|
||||
fn build(_b: &mut TypeBuilder) {}
|
||||
}
|
||||
|
||||
impl Annotation for $rty {
|
||||
fn annotation() -> impl Display {
|
||||
$lty
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_primitive!(bool, "bool");
|
||||
impl_primitive!(u8, "uint8_t");
|
||||
impl_primitive!(u16, "uint16_t");
|
||||
impl_primitive!(u32, "uint32_t");
|
||||
impl_primitive!(u64, "uint64_t");
|
||||
impl_primitive!(usize, "uintptr_t");
|
||||
impl_primitive!(i8, "int8_t");
|
||||
impl_primitive!(i16, "int16_t");
|
||||
impl_primitive!(i32, "int32_t");
|
||||
impl_primitive!(i64, "int64_t");
|
||||
impl_primitive!(isize, "intptr_t");
|
||||
impl_primitive!(c_float, "float");
|
||||
impl_primitive!(c_double, "double");
|
||||
impl_primitive!(bool, "bool", "boolean");
|
||||
impl_primitive!(u8, "uint8_t", "number");
|
||||
impl_primitive!(u16, "uint16_t", "number");
|
||||
impl_primitive!(u32, "uint32_t", "number");
|
||||
impl_primitive!(u64, "uint64_t", "number");
|
||||
impl_primitive!(usize, "uintptr_t", "number");
|
||||
impl_primitive!(i8, "int8_t", "number");
|
||||
impl_primitive!(i16, "int16_t", "number");
|
||||
impl_primitive!(i32, "int32_t", "number");
|
||||
impl_primitive!(i64, "int64_t", "number");
|
||||
impl_primitive!(isize, "intptr_t", "number");
|
||||
impl_primitive!(c_float, "float", "number");
|
||||
impl_primitive!(c_double, "double", "number");
|
||||
|
||||
unsafe impl FromFfi for bool {
|
||||
type From = bool;
|
||||
@@ -772,11 +783,19 @@ impl_bigint_intoabi!(usize);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_bigint_intoabi!(isize);
|
||||
|
||||
macro_rules! impl_const_ptr {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> Type for $ty {
|
||||
macro_rules! impl_ptr {
|
||||
($ty:ty, $mutable:expr) => {
|
||||
unsafe impl<T> Type for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
fn name() -> impl Display {
|
||||
display!("const_{}_ptr", T::name())
|
||||
disp(|f| {
|
||||
if !$mutable {
|
||||
write!(f, "const_")?;
|
||||
}
|
||||
write!(f, "{}_ptr", T::name())
|
||||
})
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
@@ -784,7 +803,12 @@ macro_rules! impl_const_ptr {
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
T::cdecl(display!("const *{name}"))
|
||||
T::cdecl(disp(move |f| {
|
||||
if !$mutable {
|
||||
write!(f, "const ")?;
|
||||
}
|
||||
write!(f, "*{name}")
|
||||
}))
|
||||
}
|
||||
|
||||
fn build(b: &mut TypeBuilder) {
|
||||
@@ -794,35 +818,44 @@ macro_rules! impl_const_ptr {
|
||||
};
|
||||
}
|
||||
|
||||
impl_const_ptr!(*const T);
|
||||
impl_const_ptr!(&T);
|
||||
impl_const_ptr!(Option<&T>);
|
||||
impl_ptr!(&T, false);
|
||||
impl_ptr!(&mut T, true);
|
||||
impl_ptr!(*const T, false);
|
||||
impl_ptr!(*mut T, true);
|
||||
impl_ptr!(Option<&T>, false);
|
||||
impl_ptr!(Option<&mut T>, true);
|
||||
|
||||
macro_rules! impl_mut_ptr {
|
||||
macro_rules! impl_ptr_annotation {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> Type for $ty {
|
||||
fn name() -> impl Display {
|
||||
display!("{}_ptr", T::name())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Primitive
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
T::cdecl(display!("*{name}"))
|
||||
}
|
||||
|
||||
fn build(b: &mut TypeBuilder) {
|
||||
b.include::<T>();
|
||||
impl<T> Annotation for $ty
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
"lightuserdata"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_mut_ptr!(*mut T);
|
||||
impl_mut_ptr!(&mut T);
|
||||
impl_mut_ptr!(Option<&mut T>);
|
||||
impl_ptr_annotation!(*const T);
|
||||
impl_ptr_annotation!(*mut T);
|
||||
|
||||
macro_rules! impl_ref_annotation {
|
||||
($ty:ty) => {
|
||||
impl<T> Annotation for $ty
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("{}", T::annotation())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_ref_annotation!(&T);
|
||||
impl_ref_annotation!(&mut T);
|
||||
|
||||
//
|
||||
// SAFETY: Pass by value for pointers, which maps to a `cdata` argument in lua containing either:
|
||||
@@ -835,7 +868,10 @@ impl_mut_ptr!(Option<&mut T>);
|
||||
//
|
||||
macro_rules! impl_ptr_fromabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> FromFfi for $ty {
|
||||
unsafe impl<T> FromFfi for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type From = Self;
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
@@ -857,7 +893,10 @@ impl_ptr_fromabi!(Option<&mut T>);
|
||||
//
|
||||
macro_rules! impl_ptr_intoabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> IntoFfi for $ty {
|
||||
unsafe impl<T> IntoFfi for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
@@ -898,7 +937,10 @@ impl_ptr_intoabi!(Option<&'static mut T>);
|
||||
//
|
||||
macro_rules! impl_ref_fromabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<'s, T: Type> FromFfi for $ty {
|
||||
unsafe impl<'s, T> FromFfi for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type From = Option<$ty>;
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
@@ -928,7 +970,10 @@ impl_ref_fromabi!(&'s mut T);
|
||||
//
|
||||
macro_rules! impl_ref_intoabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> IntoFfi for $ty {
|
||||
unsafe impl<T> IntoFfi for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
@@ -947,7 +992,10 @@ impl_ref_intoabi!(&'static mut T);
|
||||
//
|
||||
// TODO: we could automatically convert them to tables and vice-versa
|
||||
//
|
||||
unsafe impl<T: Type> Type for [T] {
|
||||
unsafe impl<T> Type for [T]
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
fn name() -> impl Display {
|
||||
display!("{}_arr", T::name())
|
||||
}
|
||||
@@ -965,7 +1013,19 @@ unsafe impl<T: Type> Type for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Type, const N: usize> Type for [T; N] {
|
||||
impl<T> Annotation for [T]
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("{}[]", T::annotation())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, const N: usize> Type for [T; N]
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
fn name() -> impl Display {
|
||||
display!("{}_arr{N}", T::name())
|
||||
}
|
||||
@@ -983,14 +1043,23 @@ unsafe impl<T: Type, const N: usize> Type for [T; N] {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UnsafeExternCFn<In, Out>(PhantomData<unsafe extern "C" fn(In) -> Out>);
|
||||
impl<T, const N: usize> Annotation for [T; N]
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("{}[]", T::annotation())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_function {
|
||||
(fn($($arg:tt),*) -> $ret:tt) => {
|
||||
impl_function!(UnsafeExternCFn, fn($($arg),*) -> $ret);
|
||||
pub struct ExternCFn<I, O>(PhantomData<extern "C" fn(I) -> O>);
|
||||
|
||||
macro_rules! impl_externcfn {
|
||||
(fn($($arg:ident),*) -> $ret:ident) => {
|
||||
impl_externcfn!(ExternCFn, fn($($arg),*) -> $ret);
|
||||
};
|
||||
|
||||
($ty:tt, fn($($arg:tt),*) -> $ret:tt) => {
|
||||
($ty:ident, fn($($arg:ident),*) -> $ret:ident) => {
|
||||
//
|
||||
// SAFETY: No `FromFfi` for function pointers because of borrow safety invariants (see above
|
||||
// in `&mut T`).
|
||||
@@ -998,7 +1067,11 @@ macro_rules! impl_function {
|
||||
// We also can't implement `IntoFfi` because we can't call `FromFfi` and `IntoFfi` for the
|
||||
// function's respective argument and return values.
|
||||
//
|
||||
unsafe impl<$($arg: Type,)* $ret: Type> Type for $ty<($($arg,)*), $ret> {
|
||||
unsafe impl<$($arg,)* $ret> Type for $ty<($($arg,)*), $ret>
|
||||
where
|
||||
$($arg: Type,)*
|
||||
$ret: Type,
|
||||
{
|
||||
fn name() -> impl Display {
|
||||
disp(|f| Ok({
|
||||
write!(f, "fn_{}", $ret::name())?;
|
||||
@@ -1012,8 +1085,8 @@ macro_rules! impl_function {
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
$ret::cdecl(disp(move |f| Ok({
|
||||
let mut _n = 0;
|
||||
write!(f, "(*{name})(")?;
|
||||
let mut _n = 0;
|
||||
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::cdecl(""))?; _n += 1;)*
|
||||
write!(f, ")")?;
|
||||
})))
|
||||
@@ -1022,8 +1095,8 @@ macro_rules! impl_function {
|
||||
fn extern_cdecl(name: impl Display) -> impl Display {
|
||||
$ret::cdecl(disp(move |f| Ok({
|
||||
// for top-level function declarations in cdef
|
||||
let mut _n = 0;
|
||||
write!(f, "{name}(")?;
|
||||
let mut _n = 0;
|
||||
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::cdecl(""))?; _n += 1;)*
|
||||
write!(f, ")")?;
|
||||
})))
|
||||
@@ -1037,11 +1110,25 @@ macro_rules! impl_function {
|
||||
};
|
||||
}
|
||||
|
||||
impl_function!(fn() -> Z);
|
||||
impl_function!(fn(A) -> Z);
|
||||
impl_function!(fn(A, B) -> Z);
|
||||
impl_function!(fn(A, B, C) -> Z);
|
||||
impl_function!(fn(A, B, C, D) -> Z);
|
||||
impl_function!(fn(A, B, C, D, E) -> Z);
|
||||
impl_function!(fn(A, B, C, D, E, F) -> Z);
|
||||
impl_function!(fn(A, B, C, D, E, F, G) -> Z);
|
||||
impl_externcfn!(fn() -> A);
|
||||
impl_externcfn!(fn(A) -> B);
|
||||
impl_externcfn!(fn(A, B) -> C);
|
||||
impl_externcfn!(fn(A, B, C) -> D);
|
||||
impl_externcfn!(fn(A, B, C, D) -> E);
|
||||
impl_externcfn!(fn(A, B, C, D, E) -> F);
|
||||
impl_externcfn!(fn(A, B, C, D, E, F) -> G);
|
||||
impl_externcfn!(fn(A, B, C, D, E, F, G) -> H);
|
||||
impl_externcfn!(fn(A, B, C, D, E, F, G, H) -> I);
|
||||
impl_externcfn!(fn(A, B, C, D, E, F, G, H, I) -> J);
|
||||
|
||||
impl<'s> Annotation for &'s str {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
}
|
||||
}
|
||||
|
||||
impl Annotation for String {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
}
|
||||
}
|
||||
|
||||
193
crates/luaffi/src/marker.rs
Normal file
193
crates/luaffi/src/marker.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::{
|
||||
__internal::{disp, display},
|
||||
Annotation,
|
||||
};
|
||||
use std::{fmt::Display, marker::PhantomData};
|
||||
|
||||
enum Marker {}
|
||||
|
||||
pub struct any(Marker);
|
||||
|
||||
impl Annotation for any {
|
||||
fn annotation() -> impl Display {
|
||||
"any"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct many(Marker);
|
||||
|
||||
impl Annotation for many {
|
||||
fn annotation() -> impl Display {
|
||||
"..."
|
||||
}
|
||||
}
|
||||
|
||||
pub struct nil(Marker);
|
||||
|
||||
impl Annotation for nil {
|
||||
fn annotation() -> impl Display {
|
||||
"nil"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct lightuserdata(Marker);
|
||||
|
||||
impl Annotation for lightuserdata {
|
||||
fn annotation() -> impl Display {
|
||||
"lightuserdata"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct table<K, V>(Marker, PhantomData<*mut [(K, V)]>);
|
||||
|
||||
impl<K, V> Annotation for table<K, V>
|
||||
where
|
||||
K: Annotation,
|
||||
V: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("table<{}, {}>", K::annotation(), V::annotation())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct function(Marker);
|
||||
|
||||
impl Annotation for function {
|
||||
fn annotation() -> impl Display {
|
||||
"function"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct fun<I, O>(Marker, PhantomData<fn(I) -> O>);
|
||||
|
||||
macro_rules! impl_fun {
|
||||
(fn($($arg:ident),*)) => {
|
||||
impl<$($arg,)*> Annotation for fun<($($arg,)*), ()>
|
||||
where
|
||||
$($arg: Annotation,)*
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
disp(|f| {
|
||||
write!(f, "fun(")?;
|
||||
let mut _n = 0;
|
||||
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::annotation())?; _n += 1;)*
|
||||
write!(f, ")")
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(fn($($arg:ident),*) -> $ret:ident) => {
|
||||
impl<$($arg,)* $ret> Annotation for fun<($($arg,)*), $ret>
|
||||
where
|
||||
$($arg: Annotation,)*
|
||||
$ret: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
disp(|f| {
|
||||
write!(f, "fun(")?;
|
||||
let mut _n = 0;
|
||||
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::annotation())?; _n += 1;)*
|
||||
write!(f, "): {}", $ret::annotation())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl_fun!(fn($($arg),*));
|
||||
};
|
||||
}
|
||||
|
||||
impl_fun!(fn() -> A);
|
||||
impl_fun!(fn(A) -> B);
|
||||
impl_fun!(fn(A, B) -> C);
|
||||
impl_fun!(fn(A, B, C) -> D);
|
||||
impl_fun!(fn(A, B, C, D) -> E);
|
||||
impl_fun!(fn(A, B, C, D, E) -> F);
|
||||
impl_fun!(fn(A, B, C, D, E, F) -> G);
|
||||
impl_fun!(fn(A, B, C, D, E, F, G) -> H);
|
||||
impl_fun!(fn(A, B, C, D, E, F, G, H) -> I);
|
||||
impl_fun!(fn(A, B, C, D, E, F, G, H, I) -> J);
|
||||
|
||||
pub struct userdata(Marker);
|
||||
|
||||
impl Annotation for userdata {
|
||||
fn annotation() -> impl Display {
|
||||
"userdata"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct thread(Marker);
|
||||
|
||||
impl Annotation for thread {
|
||||
fn annotation() -> impl Display {
|
||||
"thread"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct cdata(Marker);
|
||||
|
||||
impl Annotation for cdata {
|
||||
fn annotation() -> impl Display {
|
||||
"cdata"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Either<T, U>(Marker, PhantomData<(T, U)>);
|
||||
|
||||
impl<T, U> Annotation for Either<T, U>
|
||||
where
|
||||
T: Annotation,
|
||||
U: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("({} | {})", T::annotation(), U::annotation())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OneOf<X>(Marker, PhantomData<X>);
|
||||
|
||||
macro_rules! impl_oneof {
|
||||
($($ty:ident),+) => {
|
||||
impl<$($ty),+> Annotation for OneOf<($($ty,)+)>
|
||||
where
|
||||
$($ty: Annotation),+
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
disp(|f| {
|
||||
write!(f, "(")?;
|
||||
let mut _n = 0;
|
||||
$(if _n != 0 { write!(f, " | ")?; } write!(f, "{}", $ty::annotation())?; _n += 1;)*
|
||||
write!(f, ")")
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_oneof!(A, B);
|
||||
impl_oneof!(A, B, C);
|
||||
impl_oneof!(A, B, C, D);
|
||||
impl_oneof!(A, B, C, D, E);
|
||||
impl_oneof!(A, B, C, D, E, F);
|
||||
impl_oneof!(A, B, C, D, E, F, G);
|
||||
impl_oneof!(A, B, C, D, E, F, G, H);
|
||||
impl_oneof!(A, B, C, D, E, F, G, H, I);
|
||||
|
||||
impl<T> Annotation for Option<T>
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("{}?", T::annotation())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Annotation for Result<T, E>
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
display!("{}", T::annotation())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user