实现unified-init库,支持收集初始化函数到一个数组,并统一初始化 (#474)

* 添加“统一初始化”的过程宏,并把SystemError独立成crate

* 使用unified-init来初始化fbmem

* 更新workflow,增加内核自动化静态测试
This commit is contained in:
LoGin
2023-12-25 23:12:27 +08:00
committed by GitHub
parent f110d330d5
commit 91e9d4ab55
158 changed files with 1102 additions and 610 deletions

View File

@ -0,0 +1,14 @@
[package]
name = "unified-init"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "unified-init-expand"
path = "src/main.rs"
[dependencies]
unified-init-macros = { path = "macros" }
linkme = "0.2"
system_error = { path = "../system_error" }

View File

@ -0,0 +1,20 @@
[package]
name = "unified-init-macros"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0.71"
quote = "1.0.33"
syn = { version = "2.0.42", features = ["full"] }
uuid = { version = "0.8", features = ["v4"] }
[dev-dependencies]
unified-init = { path = ".." }
linkme = "0.2"
system_error = { path = "../../system_error" }

View File

@ -0,0 +1,230 @@
extern crate alloc;
extern crate quote;
use proc_macro::TokenStream;
use quote::quote;
use syn::{
__private::ToTokens,
parse::{self, Parse, ParseStream},
spanned::Spanned,
ItemFn, Path,
};
use uuid::Uuid;
/// 统一初始化宏,
/// 用于将函数注册到统一初始化列表中
///
/// ## 用法
///
/// ```rust
/// use system_error::SystemError;
/// use unified_init::define_unified_initializer_slice;
/// use unified_init_macros::unified_init;
///
/// /// 初始化函数都将会被放到这个列表中
/// define_unified_initializer_slice!(INITIALIZER_LIST);
///
/// #[unified_init(INITIALIZER_LIST)]
/// fn init1() -> Result<(), SystemError> {
/// Ok(())
/// }
///
/// #[unified_init(INITIALIZER_LIST)]
/// fn init2() -> Result<(), SystemError> {
/// Ok(())
/// }
///
/// fn main() {
/// assert_eq!(INITIALIZER_LIST.len(), 2);
/// }
///
/// ```
#[proc_macro_attribute]
pub fn unified_init(args: TokenStream, input: TokenStream) -> TokenStream {
do_unified_init(args, input)
.unwrap_or_else(|e| e.to_compile_error().into())
.into()
}
fn do_unified_init(args: TokenStream, input: TokenStream) -> syn::Result<proc_macro2::TokenStream> {
// 解析属性数
let attr_arg = syn::parse::<UnifiedInitArg>(args)?;
// 获取当前函数
let function = syn::parse::<ItemFn>(input)?;
// 检查函数签名
check_function_signature(&function)?;
// 添加#[::linkme::distributed_slice(attr_args.initializer_instance)]属性
let target_slice = attr_arg.initializer_instance.get_ident().unwrap();
// 在旁边添加一个UnifiedInitializer
let initializer =
generate_unified_initializer(&function, &target_slice, function.sig.ident.to_string())?;
// 拼接
let mut output = proc_macro2::TokenStream::new();
output.extend(function.into_token_stream());
output.extend(initializer);
Ok(output)
}
/// 检查函数签名是否满足要求
/// 函数签名应该为
///
/// ```rust
/// use system_error::SystemError;
/// fn xxx() -> Result<(), SystemError> {
/// Ok(())
/// }
/// ```
fn check_function_signature(function: &ItemFn) -> syn::Result<()> {
// 检查函数签名
if function.sig.inputs.len() != 0 {
return Err(syn::Error::new(
function.sig.inputs.span(),
"Expected no arguments",
));
}
if let syn::ReturnType::Type(_, ty) = &function.sig.output {
// 确认返回类型为 Result<(), SystemError>
// 解析类型
let output_type: syn::Type = syn::parse2(ty.clone().into_token_stream())?;
// 检查类型是否为 Result<(), SystemError>
if let syn::Type::Path(type_path) = output_type {
if type_path.path.segments.last().unwrap().ident == "Result" {
// 检查泛型参数,看看是否满足 Result<(), SystemError>
if let syn::PathArguments::AngleBracketed(generic_args) =
type_path.path.segments.last().unwrap().arguments.clone()
{
if generic_args.args.len() != 2 {
return Err(syn::Error::new(
generic_args.span(),
"Expected two generic arguments",
));
}
// 检查第一个泛型参数是否为()
if let syn::GenericArgument::Type(type_arg) = generic_args.args.first().unwrap()
{
if let syn::Type::Tuple(tuple) = type_arg {
if tuple.elems.len() != 0 {
return Err(syn::Error::new(tuple.span(), "Expected empty tuple"));
}
} else {
return Err(syn::Error::new(type_arg.span(), "Expected empty tuple"));
}
} else {
return Err(syn::Error::new(
generic_args.span(),
"Expected first generic argument to be a type",
));
}
// 检查第二个泛型参数是否为SystemError
if let syn::GenericArgument::Type(type_arg) = generic_args.args.last().unwrap()
{
if let syn::Type::Path(type_path) = type_arg {
if type_path.path.segments.last().unwrap().ident == "SystemError" {
// 类型匹配,返回 Ok
return Ok(());
}
}
} else {
return Err(syn::Error::new(
generic_args.span(),
"Expected second generic argument to be a type",
));
}
return Err(syn::Error::new(
generic_args.span(),
"Expected second generic argument to be SystemError",
));
}
return Ok(());
}
}
}
Err(syn::Error::new(
function.sig.output.span(),
"Expected -> Result<(), SystemError>",
))
}
/// 生成UnifiedInitializer全局变量
fn generate_unified_initializer(
function: &ItemFn,
target_slice: &syn::Ident,
raw_initializer_name: String,
) -> syn::Result<proc_macro2::TokenStream> {
let initializer_name = format!(
"unified_initializer_{}_{}",
raw_initializer_name,
Uuid::new_v4().to_simple().to_string().to_ascii_uppercase()[..8].to_string()
)
.to_ascii_uppercase();
// 获取函数的全名
let initializer_name_ident = syn::Ident::new(&initializer_name, function.sig.ident.span());
let function_ident = &function.sig.ident;
// 生成UnifiedInitializer
let initializer = quote! {
#[::linkme::distributed_slice(#target_slice)]
static #initializer_name_ident: unified_init::UnifiedInitializer = ::unified_init::UnifiedInitializer::new(#raw_initializer_name, &(#function_ident as ::unified_init::UnifiedInitFunction));
};
Ok(initializer)
}
struct UnifiedInitArg {
initializer_instance: Path,
}
impl Parse for UnifiedInitArg {
fn parse(input: ParseStream) -> parse::Result<Self> {
let mut initializer_instance = None;
while !input.is_empty() {
if initializer_instance.is_some() {
return Err(parse::Error::new(
input.span(),
"Expected exactly one initializer instance",
));
}
// 解析Ident
let ident = input.parse::<syn::Ident>()?;
// 将Ident转换为Path
let initializer = syn::Path::from(ident);
initializer_instance = Some(initializer);
}
if initializer_instance.is_none() {
return Err(parse::Error::new(
input.span(),
"Expected exactly one initializer instance",
));
}
// 判断是否为标识符
if initializer_instance.as_ref().unwrap().get_ident().is_none() {
return Err(parse::Error::new(
initializer_instance.span(),
"Expected identifier",
));
}
Ok(UnifiedInitArg {
initializer_instance: initializer_instance.unwrap(),
})
}
}

View File

@ -0,0 +1,72 @@
#![no_std]
use system_error::SystemError;
pub use unified_init_macros as macros;
/// 统一初始化器
#[derive(Debug)]
pub struct UnifiedInitializer {
function: &'static UnifiedInitFunction,
name: &'static str,
}
impl UnifiedInitializer {
pub const fn new(
name: &'static str,
function: &'static UnifiedInitFunction,
) -> UnifiedInitializer {
UnifiedInitializer { function, name }
}
/// 调用初始化函数
pub fn call(&self) -> Result<(), SystemError> {
(self.function)()
}
/// 获取初始化函数的名称
pub const fn name(&self) -> &'static str {
self.name
}
}
pub type UnifiedInitFunction = fn() -> core::result::Result<(), SystemError>;
/// 定义统一初始化器的分布式切片数组(私有)
#[macro_export]
macro_rules! define_unified_initializer_slice {
($name:ident) => {
#[::linkme::distributed_slice]
static $name: [::unified_init::UnifiedInitializer] = [..];
};
() => {
compile_error!(
"define_unified_initializer_slice! requires at least one argument: slice_name"
);
};
}
/// 定义统一初始化器的分布式切片数组(公开)
#[macro_export]
macro_rules! define_public_unified_initializer_slice {
($name:ident) => {
#[::linkme::distributed_slice]
pub static $name: [::unified_init::UnifiedInitializer] = [..];
};
() => {
compile_error!(
"define_unified_initializer_slice! requires at least one argument: slice_name"
);
};
}
/// 调用指定数组中的所有初始化器
#[macro_export]
macro_rules! unified_init {
($initializer_slice:ident) => {
for initializer in $initializer_slice.iter() {
initializer.call().unwrap_or_else(|e| {
kerror!("Failed to call initializer {}: {:?}", initializer.name(), e);
});
}
};
}

View File

@ -0,0 +1,63 @@
//! 需要测试的时候可以在这里写测试代码,
//! 然后在当前目录执行 `cargo expand --bin unified-init-expand`
//! 就可以看到把proc macro展开后的代码了
#![no_std]
fn main() {
todo!()
}
#[cfg(test)]
mod tests {
use system_error::SystemError;
use unified_init::define_unified_initializer_slice;
use unified_init_macros::unified_init;
use super::*;
#[test]
fn no_element() {
define_unified_initializer_slice!(TEST_0);
assert_eq!(TEST_0.len(), 0);
}
#[test]
fn no_element_ne() {
define_unified_initializer_slice!(TEST_0_NE);
#[unified_init(TEST_0_NE)]
fn x() -> Result<(), SystemError> {
todo!()
}
assert_ne!(TEST_0_NE.len(), 0);
}
#[test]
fn one_element() {
define_unified_initializer_slice!(TEST_1);
#[unified_init(TEST_1)]
fn x() -> Result<(), SystemError> {
todo!()
}
assert_eq!(TEST_1.len(), 1);
}
#[test]
fn two_elements() {
define_unified_initializer_slice!(TEST_2);
#[unified_init(TEST_2)]
fn x() -> Result<(), SystemError> {
todo!()
}
#[unified_init(TEST_2)]
fn y() -> Result<(), SystemError> {
todo!()
}
assert_eq!(TEST_2.len(), 2);
}
}