-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,797 additions
and
583 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
#![feature(trivial_bounds)] | ||
|
||
use getset::Getters; | ||
use iroha_ffi::decl_ffi_fns; | ||
use iroha_ffi_derive::{ffi, ffi_export, ffi_import}; | ||
|
||
ffi! { | ||
#[derive(Getters)] | ||
#[getset(get = "pub")] | ||
#[ffi_type(opaque)] | ||
pub struct A { | ||
a: i32, | ||
} | ||
} | ||
|
||
// #[repr(transparent)] | ||
// pub struct A(*mut iroha_ffi::Extern) where A: iroha_ffi::Handle; | ||
// #[derive(Clone, Copy)] | ||
// #[repr(transparent)] | ||
// pub struct RefA<'a> (*const iroha_ffi::Extern, core::marker::PhantomData<&'a ()>) where A: iroha_ffi::Handle; | ||
// #[repr(transparent)] | ||
// pub struct RefMutA<'a> (*mut iroha_ffi::Extern, core::marker::PhantomData<&'a mut ()>) where A: iroha_ffi::Handle; | ||
// impl Drop for A where A: iroha_ffi::Handle { | ||
// fn drop(&mut self) { | ||
// let handle_id = iroha_ffi::FfiConvert::into_ffi(<A as iroha_ffi::Handle>::ID, &mut ()); | ||
// let drop_result = unsafe { crate::__drop(handle_id, self.0) }; | ||
// if drop_result != iroha_ffi::FfiReturn::Ok { panic!("Drop returned: {}", drop_result); } | ||
// } | ||
// } | ||
// impl A where A: iroha_ffi::Handle { fn from_extern_ptr(opaque_ptr: *mut iroha_ffi::Extern) -> Self { Self(opaque_ptr) } } | ||
// impl<'a> A where A: iroha_ffi::Handle { | ||
// fn as_ref(&self) -> RefA<'a> { RefA(self.0, core::marker::PhantomData) } | ||
// fn as_mut(&mut self) -> RefMutA<'a> where A: iroha_ffi::Handle { RefMutA(self.0, core::marker::PhantomData) } | ||
// } | ||
// impl<'a> core::ops::Deref for RefA<'a> where A: iroha_ffi::Handle { | ||
// type Target = A; | ||
// fn deref(&self) -> &Self::Target { unsafe { &*(&self.0 as *const *const iroha_ffi::Extern).cast() } } | ||
// } | ||
// impl<'a> core::ops::Deref for RefMutA<'a> where A: iroha_ffi::Handle { | ||
// type Target = RefA<'a>; | ||
// fn deref(&self) -> &Self::Target { unsafe { &*(&self.0 as *const *mut iroha_ffi::Extern).cast() } } | ||
// } | ||
// impl<'a> core::ops::DerefMut for RefMutA<'a> where A: iroha_ffi::Handle { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(&mut self.0 as *mut *mut iroha_ffi::Extern).cast() } } } | ||
// unsafe impl iroha_ffi::ir::External for A where A: iroha_ffi::Handle { | ||
// type RefType<'a> = RefA<'a>; | ||
// type RefMutType<'a> = RefMutA<'a>; | ||
// fn as_extern_ptr(&self) -> *const iroha_ffi::Extern { self.0 } | ||
// fn as_extern_ptr_mut(&mut self) -> *mut iroha_ffi::Extern { self.0 } | ||
// unsafe fn from_extern_ptr(opaque_ptr: *mut iroha_ffi::Extern) -> Self { Self::from_extern_ptr(opaque_ptr) } | ||
// } | ||
// unsafe impl iroha_ffi::ir::Transmute for A where A: iroha_ffi::Handle { | ||
// type Target = *mut iroha_ffi::Extern; | ||
// #[inline] | ||
// unsafe fn is_valid(target: &Self::Target) -> bool { !target.is_null() } | ||
// } | ||
// impl iroha_ffi::ir::Ir for A where A: iroha_ffi::Handle { type Type = Self; } | ||
// impl iroha_ffi::repr_c::CType<Self> for A where A: iroha_ffi::Handle { type ReprC = *mut iroha_ffi::Extern; } | ||
// impl iroha_ffi::repr_c::CTypeConvert<'_, Self, *mut iroha_ffi::Extern> for A where A: iroha_ffi::Handle { | ||
// type RustStore = (); | ||
// type FfiStore = (); | ||
// fn into_repr_c(self, _: &mut ()) -> *mut iroha_ffi::Extern { core::mem::ManuallyDrop::new(self).0 } | ||
// unsafe fn try_from_repr_c(source: *mut iroha_ffi::Extern, _: &mut ()) -> iroha_ffi::Result<Self> { | ||
// if source.is_null() { return Err(iroha_ffi::FfiReturn::ArgIsNull); } | ||
// Ok(Self::from_extern_ptr(source)) | ||
// } | ||
// } | ||
// impl iroha_ffi::repr_c::CWrapperType<Self> for A where A: iroha_ffi::Handle { | ||
// type InputType = Self; | ||
// type ReturnType = Self; | ||
// } | ||
// impl iroha_ffi::repr_c::COutPtr<Self> for A where A: iroha_ffi::Handle { type OutPtr = Self::ReprC; } | ||
// impl iroha_ffi::repr_c::COutPtrRead<Self> for A where A: iroha_ffi::Handle { unsafe fn try_read_out(out_ptr: Self::OutPtr) -> iroha_ffi::Result<Self> { iroha_ffi::repr_c::read_non_local::<_, Self>(out_ptr) } } | ||
// impl iroha_ffi::ir::IrTypeFamily for A where A: iroha_ffi::Handle { | ||
// type Ref<'a> = &'a iroha_ffi::Extern where; | ||
// type RefMut<'a> = &'a mut iroha_ffi::Extern where; | ||
// type Box = Box<iroha_ffi::Extern>; | ||
// type SliceRef<'a> = &'a [iroha_ffi::ir::Transparent] where; | ||
// type SliceRefMut<'a> = &'a mut [iroha_ffi::ir::Transparent] where; | ||
// type Vec = Vec<iroha_ffi::ir::Transparent>; | ||
// type Arr<const N: usize> = iroha_ffi::ir::Transparent; | ||
// } | ||
// unsafe impl iroha_ffi::repr_c::NonLocal<Self> for A where A: iroha_ffi::Handle {} | ||
// impl<'a> ::iroha_ffi::ir::Ir for RefA<'a> where A: iroha_ffi::Handle { | ||
// type Type = ::iroha_ffi::ir::Transparent; | ||
// } | ||
// unsafe impl<'a> ::iroha_ffi::ir::Transmute for RefA<'a> where A: iroha_ffi::Handle { | ||
// type Target = *const iroha_ffi::Extern; | ||
// | ||
// #[inline] | ||
// unsafe fn is_valid(target: &Self::Target) -> bool { | ||
// (|target: &*const iroha_ffi::Extern| !target.is_null())(target) | ||
// } | ||
// } | ||
// impl<'a> ::iroha_ffi::option::Niche<'_> for RefA<'a> where A: iroha_ffi::Handle { | ||
// const NICHE_VALUE: <*const iroha_ffi::Extern as ::iroha_ffi::FfiType>::ReprC = (core::ptr::null()); | ||
// } | ||
// impl<'a> ::iroha_ffi::ir::Ir for RefMutA<'a> where A: iroha_ffi::Handle { | ||
// type Type = ::iroha_ffi::ir::Transparent; | ||
// } | ||
// unsafe impl<'a> ::iroha_ffi::ir::Transmute for RefMutA<'a> where A: iroha_ffi::Handle { | ||
// type Target = *mut iroha_ffi::Extern; | ||
// | ||
// #[inline] | ||
// unsafe fn is_valid(target: &Self::Target) -> bool { | ||
// (|target: &*mut iroha_ffi::Extern| !target.is_null())(target) | ||
// } | ||
// } | ||
// impl<'a> ::iroha_ffi::option::Niche<'_> for RefMutA<'a> where A: iroha_ffi::Handle { | ||
// const NICHE_VALUE: <*mut iroha_ffi::Extern as ::iroha_ffi::FfiType>::ReprC = (core::ptr::null_mut()); | ||
// } | ||
// unsafe impl iroha_ffi::ir::InfallibleTransmute for A where A: iroha_ffi::Handle {} | ||
// unsafe impl<'a> iroha_ffi::ir::InfallibleTransmute for RefA<'a> where A: iroha_ffi::Handle {} | ||
// unsafe impl<'a> iroha_ffi::ir::InfallibleTransmute for RefMutA<'a> where A: iroha_ffi::Handle {} | ||
// impl iroha_ffi::WrapperTypeOf<Self> for A where A: iroha_ffi::Handle { type Type = Self; } | ||
// impl<'a> iroha_ffi::WrapperTypeOf<&'a A> for RefA<'a> where A: iroha_ffi::Handle { type Type = Self; } | ||
// impl<'a> iroha_ffi::WrapperTypeOf<&'a mut A> for RefMutA<'a> where A: iroha_ffi::Handle { type Type = Self; } | ||
// impl iroha_ffi::option::Niche<'_> for A where A: iroha_ffi::Handle { const NICHE_VALUE: *mut iroha_ffi::Extern = core::ptr::null_mut(); } | ||
// impl A { | ||
// pub fn a(&self: <&Self as iroha_ffi::FfiWrapperType>::InputType) -> <&i32 as iroha_ffi::FfiWrapperType>::ReturnType { self.as_ref().a() } | ||
// } | ||
// impl<'a> RefA<'a> { | ||
// pub fn a(&self: <&Self as iroha_ffi::FfiWrapperType>::InputType) -> <&'a i32 as iroha_ffi::FfiWrapperType>::ReturnType { | ||
// let __handle = self; | ||
// let __handle = __handle.0; | ||
// let mut __handle_store = Default::default(); | ||
// let __handle = iroha_ffi::FfiConvert::into_ffi(__handle, &mut __handle_store); | ||
// let mut a = core::mem::MaybeUninit::uninit(); | ||
// unsafe { | ||
// let __ffi_return = A__a(__handle, a.as_mut_ptr()); | ||
// match __ffi_return { | ||
// iroha_ffi::FfiReturn::Ok => {} | ||
// _ => panic!(concat!(stringify!(A__a ), " returned {}" ), __ffi_return) | ||
// } | ||
// let a = a.assume_init(); | ||
// let a = iroha_ffi::FfiOutPtrRead::try_read_out(a).expect("Invalid out-pointer value returned"); | ||
// a | ||
// } | ||
// } | ||
// } | ||
// extern { | ||
// #[doc = " FFI function equivalent of [`A::a`]\n \n # Safety\n \n All of the given pointers must be valid"] | ||
// fn A__a(__handle: <<&A as iroha_ffi::FfiWrapperType>::InputType as iroha_ffi::FfiType>::ReprC, a: *mut <<&i32 as iroha_ffi::FfiWrapperType>::ReturnType as iroha_ffi::FfiOutPtr>::OutPtr) -> iroha_ffi::FfiReturn; | ||
// } | ||
// | ||
// iroha_ffi::decl_ffi_fns! { link_prefix="iroha_aboba" Drop, Clone, Eq, Ord, Default } | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
//! This module provides parsing of `#[derive(...)]` attributes | ||
|
||
use darling::FromAttributes; | ||
use quote::ToTokens; | ||
use syn2::{punctuated::Punctuated, Attribute, Token}; | ||
|
||
use super::getset::GetSetDerive; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
pub enum RustcDerive { | ||
Eq, | ||
PartialEq, | ||
Ord, | ||
PartialOrd, | ||
Clone, | ||
Copy, | ||
Hash, | ||
Default, | ||
Debug, | ||
} | ||
|
||
impl RustcDerive { | ||
fn try_from_path(path: &syn2::Path) -> Option<Self> { | ||
let Some(ident) = path.get_ident() else { | ||
return None; | ||
}; | ||
|
||
match ident.to_string().as_str() { | ||
"Eq" => Some(Self::Eq), | ||
"PartialEq" => Some(Self::PartialEq), | ||
"Ord" => Some(Self::Ord), | ||
"PartialOrd" => Some(Self::PartialOrd), | ||
"Clone" => Some(Self::Clone), | ||
"Copy" => Some(Self::Copy), | ||
"Hash" => Some(Self::Hash), | ||
"Default" => Some(Self::Default), | ||
"Debug" => Some(Self::Debug), | ||
_ => None, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub enum Derive { | ||
Rustc(RustcDerive), | ||
GetSet(GetSetDerive), | ||
Other(String), | ||
} | ||
|
||
/// Represents a collection of all `#[derive(...)]` attributes placed on the item | ||
/// | ||
/// NOTE: strictly speaking, correctly parsing this is impossible, since it requires | ||
/// us to resolve the paths in the attributes, which is not possible in a proc-macro context. | ||
/// | ||
/// We just __hope__ that the user refers to the derives by their canonical names (no aliases). | ||
/// | ||
/// This, however, will mistakingly thing that `derive_more` derives are actually rustc's built-in ones. | ||
/// | ||
/// Care should be taken, and it should be documented in the macro APIs that use this. | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub struct DeriveAttr { | ||
pub derives: Vec<Derive>, | ||
} | ||
|
||
impl FromAttributes for DeriveAttr { | ||
fn from_attributes(attrs: &[Attribute]) -> darling::Result<Self> { | ||
let mut derives = Vec::new(); | ||
let mut accumulator = darling::error::Accumulator::default(); | ||
|
||
for attr in attrs { | ||
if attr.path().is_ident("derive") { | ||
let Some(list) = accumulator.handle(attr.meta.require_list().map_err(Into::into)) else { | ||
continue | ||
}; | ||
let Some(paths) = accumulator.handle( | ||
list.parse_args_with(Punctuated::<syn2::Path, Token![,]>::parse_terminated).map_err(Into::into) | ||
) else { | ||
continue | ||
}; | ||
|
||
for path in paths { | ||
let derive = if let Some(derive) = RustcDerive::try_from_path(&path) { | ||
Derive::Rustc(derive) | ||
} else if let Some(derive) = GetSetDerive::try_from_path(&path) { | ||
Derive::GetSet(derive) | ||
} else { | ||
Derive::Other(path.to_token_stream().to_string()) | ||
}; | ||
|
||
// I __think__ it's an error to use the same derive twice | ||
// I don't think we care in this case though | ||
derives.push(derive); | ||
} | ||
} | ||
} | ||
|
||
accumulator.finish_with(Self { derives }) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use darling::FromAttributes; | ||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use syn2::parse::ParseStream; | ||
|
||
use super::{Derive, DeriveAttr, GetSetDerive, RustcDerive}; | ||
|
||
fn parse_derives(attrs: TokenStream) -> darling::Result<DeriveAttr> { | ||
struct Attributes(Vec<syn2::Attribute>); | ||
|
||
impl syn2::parse::Parse for Attributes { | ||
fn parse(input: ParseStream) -> syn2::Result<Self> { | ||
Ok(Self(input.call(syn2::Attribute::parse_outer)?)) | ||
} | ||
} | ||
|
||
let attrs = syn2::parse2::<Attributes>(attrs) | ||
.expect("Failed to parse tokens as outer attributes") | ||
.0; | ||
DeriveAttr::from_attributes(&attrs) | ||
} | ||
|
||
macro_rules! assert_derive_ok { | ||
($( #[$meta:meta] )*, | ||
$expected:expr | ||
) => { | ||
assert_eq!(parse_derives(quote!( | ||
$( #[$meta] )* | ||
)).unwrap(), | ||
$expected | ||
) | ||
}; | ||
} | ||
|
||
#[test] | ||
fn derive_rustc() { | ||
assert_derive_ok!( | ||
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Default, Debug)], | ||
DeriveAttr { | ||
derives: vec![ | ||
RustcDerive::Eq, | ||
RustcDerive::PartialEq, | ||
RustcDerive::Ord, | ||
RustcDerive::PartialOrd, | ||
RustcDerive::Clone, | ||
RustcDerive::Copy, | ||
RustcDerive::Hash, | ||
RustcDerive::Default, | ||
RustcDerive::Debug, | ||
].into_iter().map(Derive::Rustc).collect(), | ||
} | ||
) | ||
} | ||
|
||
#[test] | ||
fn derive_getset() { | ||
assert_derive_ok!( | ||
#[derive(Getters, Setters, MutGetters, CopyGetters)], | ||
DeriveAttr { | ||
derives: vec![ | ||
GetSetDerive::Getters, | ||
GetSetDerive::Setters, | ||
GetSetDerive::MutGetters, | ||
GetSetDerive::CopyGetters, | ||
].into_iter().map(Derive::GetSet).collect(), | ||
} | ||
) | ||
} | ||
|
||
#[test] | ||
fn derive_unknown() { | ||
assert_derive_ok!( | ||
#[derive(Aboba, Kek)], | ||
DeriveAttr { | ||
derives: vec![ | ||
"Aboba".to_string(), | ||
"Kek".to_string(), | ||
].into_iter().map(Derive::Other).collect(), | ||
} | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
use darling::FromAttributes; | ||
use syn2::Attribute; | ||
|
||
pub struct DocAttrs { | ||
pub attrs: Vec<Attribute>, | ||
} | ||
|
||
impl FromAttributes for DocAttrs { | ||
fn from_attributes(attrs: &[Attribute]) -> darling::Result<Self> { | ||
let mut docs = Vec::new(); | ||
for attr in attrs { | ||
if attr.path().is_ident("doc") { | ||
docs.push(attr.clone()); | ||
} | ||
} | ||
Ok(DocAttrs { attrs: docs }) | ||
} | ||
} |
Oops, something went wrong.