mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 08:06:32 +00:00
实现unified-init库,支持收集初始化函数到一个数组,并统一初始化 (#474)
* 添加“统一初始化”的过程宏,并把SystemError独立成crate * 使用unified-init来初始化fbmem * 更新workflow,增加内核自动化静态测试
This commit is contained in:
12
kernel/crates/system_error/Cargo.toml
Normal file
12
kernel/crates/system_error/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "system_error"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
kdepends = { path = "../kdepends" }
|
||||
num-traits = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
|
||||
num = { version = "0.4.0", default-features = false }
|
||||
num-derive = "0.3"
|
312
kernel/crates/system_error/src/lib.rs
Normal file
312
kernel/crates/system_error/src/lib.rs
Normal file
@ -0,0 +1,312 @@
|
||||
#![no_std]
|
||||
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, Eq, Clone)]
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
pub enum SystemError {
|
||||
/// 操作不被允许 Operation not permitted.
|
||||
EPERM = 1,
|
||||
/// 没有指定的文件或目录 No such file or directory.
|
||||
ENOENT = 2,
|
||||
/// 没有这样的进程 No such process.
|
||||
ESRCH = 3,
|
||||
/// 被中断的函数 Interrupted function.
|
||||
EINTR = 4,
|
||||
/// I/O错误 I/O error.
|
||||
EIO = 5,
|
||||
/// 没有这样的设备或地址 No such device or address.
|
||||
ENXIO = 6,
|
||||
/// 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long.
|
||||
E2BIG = 7,
|
||||
/// 可执行文件格式错误 Executable file format error
|
||||
ENOEXEC = 8,
|
||||
/// 错误的文件描述符 Bad file descriptor.
|
||||
EBADF = 9,
|
||||
/// 没有子进程 No child processes.
|
||||
ECHILD = 10,
|
||||
/// 资源不可用,请重试。 Resource unavailable, try again.(may be the same value as [EWOULDBLOCK])
|
||||
///
|
||||
/// 操作将被禁止 Operation would block.(may be the same value as [EAGAIN]).
|
||||
EAGAIN_OR_EWOULDBLOCK = 11,
|
||||
/// 没有足够的空间 Not enough space.
|
||||
ENOMEM = 12,
|
||||
/// 访问被拒绝 Permission denied
|
||||
EACCES = 13,
|
||||
/// 错误的地址 Bad address
|
||||
EFAULT = 14,
|
||||
/// 需要块设备 Block device required
|
||||
ENOTBLK = 15,
|
||||
/// 设备或资源忙 Device or resource busy.
|
||||
EBUSY = 16,
|
||||
/// 文件已存在 File exists.
|
||||
EEXIST = 17,
|
||||
/// 跨设备连接 Cross-device link.
|
||||
EXDEV = 18,
|
||||
/// 没有指定的设备 No such device.
|
||||
ENODEV = 19,
|
||||
/// 不是目录 Not a directory.
|
||||
ENOTDIR = 20,
|
||||
/// 是一个目录 Is a directory
|
||||
EISDIR = 21,
|
||||
/// 不可用的参数 Invalid argument.
|
||||
EINVAL = 22,
|
||||
/// 系统中打开的文件过多 Too many files open in system.
|
||||
ENFILE = 23,
|
||||
/// 文件描述符的值过大 File descriptor value too large.
|
||||
EMFILE = 24,
|
||||
/// 不正确的I/O控制操作 Inappropriate I/O control operation.
|
||||
ENOTTY = 25,
|
||||
/// 文本文件忙 Text file busy.
|
||||
ETXTBSY = 26,
|
||||
/// 文件太大 File too large.
|
||||
EFBIG = 27,
|
||||
/// 设备上没有空间 No space left on device.
|
||||
ENOSPC = 28,
|
||||
/// 错误的寻道.当前文件是pipe,不允许seek请求 Invalid seek.
|
||||
ESPIPE = 29,
|
||||
/// 只读的文件系统 Read-only file system.
|
||||
EROFS = 30,
|
||||
/// 链接数过多 Too many links.
|
||||
EMLINK = 31,
|
||||
/// 断开的管道 Broken pipe.
|
||||
EPIPE = 32,
|
||||
/// 数学参数超出作用域 Mathematics argument out of domain of function.
|
||||
EDOM = 33,
|
||||
/// 结果过大 Result too large.
|
||||
ERANGE = 34,
|
||||
/// 资源死锁将要发生 Resource deadlock would occur.
|
||||
EDEADLK = 35,
|
||||
/// 文件名过长 Filename too long.
|
||||
ENAMETOOLONG = 36,
|
||||
/// 没有可用的锁 No locks available.
|
||||
ENOLCK = 37,
|
||||
/// 功能不支持 Function not supported.
|
||||
ENOSYS = 38,
|
||||
/// 目录非空 Directory not empty.
|
||||
ENOTEMPTY = 39,
|
||||
/// 符号链接级别过多 Too many levels of symbolic links.
|
||||
ELOOP = 40,
|
||||
/// 没有期待类型的消息 No message of the desired type.
|
||||
ENOMSG = 41,
|
||||
/// 标志符被移除 Identifier removed.
|
||||
EIDRM = 42,
|
||||
/// 通道号超出范围 Channel number out of range
|
||||
ECHRNG = 43,
|
||||
/// 二级不同步 Level 2 not synchronized
|
||||
EL2NSYNC = 44,
|
||||
/// 三级暂停 Level 3 halted
|
||||
EL3HLT = 45,
|
||||
/// 三级重置 Level 3 reset
|
||||
EL3RST = 46,
|
||||
/// 链接号超出范围 Link number out of range
|
||||
ELNRNG = 47,
|
||||
/// 未连接协议驱动程序 Protocol driver not attached
|
||||
EUNATCH = 48,
|
||||
/// 没有可用的CSI结构 No CSI structure available
|
||||
ENOCSI = 49,
|
||||
/// 二级暂停 Level 2 halted
|
||||
EL2HLT = 50,
|
||||
/// 无效交换 Invalid exchange
|
||||
EBADE = 51,
|
||||
/// 无效的请求描述符 Invalid request descriptor
|
||||
EBADR = 52,
|
||||
/// 交换满 Exchange full
|
||||
EXFULL = 53,
|
||||
/// 无阳极 No anode
|
||||
ENOANO = 54,
|
||||
/// 请求码无效 Invalid request code
|
||||
EBADRQC = 55,
|
||||
/// 无效插槽 Invalid slot
|
||||
EBADSLT = 56,
|
||||
/// 资源死锁 Resource deadlock would occur
|
||||
EDEADLOCK = 57,
|
||||
/// 错误的字体文件格式 Bad font file format
|
||||
EBFONT = 58,
|
||||
/// 不是STREAM Not a STREAM
|
||||
ENOSTR = 59,
|
||||
/// 队列头没有可读取的消息 No message is available on the STREAM head read queue.
|
||||
ENODATA = 60,
|
||||
/// 流式ioctl()超时 Stream ioctl() timeout
|
||||
ETIME = 61,
|
||||
/// 没有STREAM资源 No STREAM resources.
|
||||
ENOSR = 62,
|
||||
/// 机器不在网络上 Machine is not on the network
|
||||
ENONET = 63,
|
||||
/// 未安装软件包 Package not installed
|
||||
ENOPKG = 64,
|
||||
/// 远程对象 Object is remote
|
||||
EREMOTE = 65,
|
||||
/// 保留 Reserved.
|
||||
ENOLINK = 66,
|
||||
/// 外设错误 Advertise error.
|
||||
EADV = 67,
|
||||
/// 安装错误 Srmount error
|
||||
ESRMNT = 68,
|
||||
/// 发送时发生通信错误 Communication error on send
|
||||
ECOMM = 69,
|
||||
/// 协议错误 Protocol error.
|
||||
EPROTO = 70,
|
||||
/// 保留使用 Reserved.
|
||||
EMULTIHOP = 71,
|
||||
/// RFS特定错误 RFS specific error
|
||||
EDOTDOT = 72,
|
||||
/// 错误的消息 Bad message.
|
||||
EBADMSG = 73,
|
||||
/// 数值过大,产生溢出 Value too large to be stored in data type.
|
||||
EOVERFLOW = 74,
|
||||
/// 名称在网络上不是唯一的 Name not unique on network
|
||||
ENOTUNIQ = 75,
|
||||
/// 处于不良状态的文件描述符 File descriptor in bad state
|
||||
EBADFD = 76,
|
||||
/// 远程地址已更改 Remote address changed
|
||||
EREMCHG = 77,
|
||||
/// 无法访问所需的共享库 Can not access a needed shared library
|
||||
ELIBACC = 78,
|
||||
/// 访问损坏的共享库 Accessing a corrupted shared library
|
||||
ELIBBAD = 79,
|
||||
/// a. out中的.lib部分已损坏 .lib section in a.out corrupted
|
||||
ELIBSCN = 80,
|
||||
/// 尝试链接太多共享库 Attempting to link in too many shared libraries
|
||||
ELIBMAX = 81,
|
||||
/// 无法直接执行共享库 Cannot exec a shared library directly
|
||||
ELIBEXEC = 82,
|
||||
/// 不合法的字符序列 Illegal byte sequence.
|
||||
EILSEQ = 83,
|
||||
/// 中断的系统调用应该重新启动 Interrupted system call should be restarted
|
||||
ERESTART = 84,
|
||||
/// 流管道错误 Streams pipe error
|
||||
ESTRPIPE = 85,
|
||||
/// 用户太多 Too many users
|
||||
EUSERS = 86,
|
||||
/// 不是一个套接字 Not a socket.
|
||||
ENOTSOCK = 87,
|
||||
/// 需要目标地址 Destination address required.
|
||||
EDESTADDRREQ = 88,
|
||||
/// 消息过大 Message too large.
|
||||
EMSGSIZE = 89,
|
||||
/// 对于套接字而言,错误的协议 Protocol wrong type for socket.
|
||||
EPROTOTYPE = 90,
|
||||
/// 协议不可用 Protocol not available.
|
||||
ENOPROTOOPT = 91,
|
||||
/// 协议不被支持 Protocol not supported.
|
||||
EPROTONOSUPPORT = 92,
|
||||
/// 不支持套接字类型 Socket type not supported
|
||||
ESOCKTNOSUPPORT = 93,
|
||||
/// 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]).
|
||||
///
|
||||
/// 不被支持 Not supported (may be the same value as [EOPNOTSUPP]).
|
||||
EOPNOTSUPP_OR_ENOTSUP = 94,
|
||||
/// 不支持协议系列 Protocol family not supported
|
||||
EPFNOSUPPORT = 95,
|
||||
/// 地址family不支持 Address family not supported.
|
||||
EAFNOSUPPORT = 96,
|
||||
/// 地址正在被使用 Address in use.
|
||||
EADDRINUSE = 97,
|
||||
/// 地址不可用 Address not available.
|
||||
EADDRNOTAVAIL = 98,
|
||||
/// 网络已关闭 Network is down.
|
||||
ENETDOWN = 99,
|
||||
/// 网络不可达 Network unreachable.
|
||||
ENETUNREACH = 100,
|
||||
/// 网络连接已断开 Connection aborted by network.
|
||||
ENETRESET = 101,
|
||||
/// 连接已断开 Connection aborted.
|
||||
ECONNABORTED = 102,
|
||||
/// 连接被重置 Connection reset.
|
||||
ECONNRESET = 103,
|
||||
/// 缓冲区空间不足 No buffer space available.
|
||||
ENOBUFS = 104,
|
||||
/// 套接字已连接 Socket is connected.
|
||||
EISCONN = 105,
|
||||
/// 套接字未连接 The socket is not connected.
|
||||
ENOTCONN = 106,
|
||||
/// 传输端点关闭后无法发送 Cannot send after transport endpoint shutdown
|
||||
ESHUTDOWN = 107,
|
||||
/// 引用太多:无法拼接 Too many references: cannot splice
|
||||
ETOOMANYREFS = 108,
|
||||
/// 连接超时 Connection timed out.
|
||||
ETIMEDOUT = 109,
|
||||
/// 连接被拒绝 Connection refused.
|
||||
ECONNREFUSED = 110,
|
||||
/// 主机已关闭 Host is down
|
||||
EHOSTDOWN = 111,
|
||||
/// 主机不可达 Host is unreachable.
|
||||
EHOSTUNREACH = 112,
|
||||
/// 连接已经在处理 Connection already in progress.
|
||||
EALREADY = 113,
|
||||
/// 操作正在处理 Operation in progress.
|
||||
EINPROGRESS = 114,
|
||||
/// 保留 Reserved.
|
||||
ESTALE = 115,
|
||||
/// 结构需要清理 Structure needs cleaning
|
||||
EUCLEAN = 116,
|
||||
/// 不是XENIX命名类型文件 Not a XENIX named type file
|
||||
ENOTNAM = 117,
|
||||
/// 没有可用的XENIX信号量 No XENIX semaphores available
|
||||
ENAVAIL = 118,
|
||||
/// 是命名类型文件 Is a named type file
|
||||
EISNAM = 119,
|
||||
/// 远程I/O错误 Remote I/O error
|
||||
EREMOTEIO = 120,
|
||||
/// 保留使用 Reserved
|
||||
EDQUOT = 121,
|
||||
/// 没有找到媒介 No medium found
|
||||
ENOMEDIUM = 122,
|
||||
/// 介质类型错误 Wrong medium type
|
||||
EMEDIUMTYPE = 123,
|
||||
/// 操作被取消 Operation canceled.
|
||||
ECANCELED = 124,
|
||||
/// 所需的密钥不可用 Required key not available
|
||||
ENOKEY = 125,
|
||||
/// 密钥已过期 Key has expired
|
||||
EKEYEXPIRED = 126,
|
||||
/// 密钥已被撤销 Key has been revoked
|
||||
EKEYREVOKED = 127,
|
||||
/// 密钥被服务拒绝 Key has been revoked
|
||||
EKEYREJECTED = 128,
|
||||
/// 之前的拥有者挂了 Previous owner died.
|
||||
EOWNERDEAD = 129,
|
||||
/// 状态不可恢复 State not recoverable.
|
||||
ENOTRECOVERABLE = 130,
|
||||
// VMX on 虚拟化开启指令出错
|
||||
EVMXONFailed = 131,
|
||||
// VMX off 虚拟化关闭指令出错
|
||||
EVMXOFFFailed = 132,
|
||||
// VMX VMWRITE 写入虚拟化VMCS内存出错
|
||||
EVMWRITEFailed = 133,
|
||||
EVMREADFailed = 134,
|
||||
EVMPRTLDFailed = 135,
|
||||
EVMLAUNCHFailed = 136,
|
||||
KVM_HVA_ERR_BAD = 137,
|
||||
|
||||
// === 以下错误码不应该被用户态程序使用 ===
|
||||
ERESTARTSYS = 512,
|
||||
}
|
||||
|
||||
impl SystemError {
|
||||
/// @brief 把posix错误码转换为系统错误枚举类型。
|
||||
pub fn from_posix_errno(errno: i32) -> Option<SystemError> {
|
||||
// posix 错误码是小于0的
|
||||
if errno >= 0 {
|
||||
return None;
|
||||
}
|
||||
return <Self as num_traits::FromPrimitive>::from_i32(-errno);
|
||||
}
|
||||
|
||||
/// @brief 把系统错误枚举类型转换为负数posix错误码。
|
||||
pub fn to_posix_errno(&self) -> i32 {
|
||||
return -<Self as num_traits::ToPrimitive>::to_i32(self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(SystemError::EPERM.to_posix_errno(), -1);
|
||||
}
|
||||
}
|
14
kernel/crates/unified-init/Cargo.toml
Normal file
14
kernel/crates/unified-init/Cargo.toml
Normal 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" }
|
20
kernel/crates/unified-init/macros/Cargo.toml
Normal file
20
kernel/crates/unified-init/macros/Cargo.toml
Normal 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" }
|
230
kernel/crates/unified-init/macros/src/lib.rs
Normal file
230
kernel/crates/unified-init/macros/src/lib.rs
Normal 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(),
|
||||
})
|
||||
}
|
||||
}
|
72
kernel/crates/unified-init/src/lib.rs
Normal file
72
kernel/crates/unified-init/src/lib.rs
Normal 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);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
63
kernel/crates/unified-init/src/main.rs
Normal file
63
kernel/crates/unified-init/src/main.rs
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user