Refactor project structure

This commit is contained in:
Zhang Junyang
2024-02-27 16:40:16 +08:00
committed by Tate, Hongliang Tian
parent bd878dd1c9
commit e3c227ae06
474 changed files with 77 additions and 77 deletions

2
kernel/libs/int-to-c-enum/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

View File

@ -0,0 +1,13 @@
[package]
name = "int-to-c-enum"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
int-to-c-enum-derive = { path = "derive", optional = true }
[features]
default = ["derive"]
derive = ["int-to-c-enum-derive"]

View File

@ -0,0 +1,35 @@
# TryFromInt - A convenient derive macro for converting an integer to an enum
## Quick Start
To use this crate, first add this crate to your `Cargo.toml`.
```toml
[dependencies]
int-to-c-enum = "0.1.0"
```
You can use this macro for a [C-like enum](https://doc.rust-lang.org/stable/rust-by-example/custom_types/enum/c_like.html).
```rust
use int_to_c_enum::TryFromInt;
#[repr(u8)]
#[derive(TryFromInt, Debug)]
pub enum Color {
Red = 1,
Blue = 2,
Green = 3,
}
```
Then, you can use `try_from` function for this enum.
```rust
fn main() {
let color = Color::try_from(1).unwrap();
println!("color = {color:?}"); // color = Red;
}
```
## Introduction
This crate provides a derive procedural macro named `TryFromInt`. This macro will automatically implement [TryFrom](https://doc.rust-lang.org/core/convert/trait.TryFrom.html) trait for enums that meet the following requirements:
1. The enum must have a primitive repr, i.e., the enum should have attribute like #[repr(u8)], #[repr(u32)], etc. The type parameter of TryFrom will be the repr, e.g., in the `QuickStart` example, the macro will implment `TryFrom<u8>` for `Color`.
2. The enum must consist solely of unit variants, which is called [units only enum](https://doc.rust-lang.org/reference/items/enumerations.html#unit-only-enum). Each field should have an **explicit discriminant**.

View File

@ -0,0 +1,14 @@
[package]
name = "int-to-c-enum-derive"
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"
quote = "1.0"
syn = { version = "2.0.15", features = ["parsing"] }

View File

@ -0,0 +1,110 @@
// SPDX-License-Identifier: MPL-2.0
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, TokenStreamExt};
use syn::{parse_macro_input, Attribute, Data, DataEnum, DeriveInput, Generics};
const ALLOWED_REPRS: &[&str] = &[
"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize",
];
const VALUE_NAME: &str = "value";
const REPR_PATH: &str = "repr";
#[proc_macro_derive(TryFromInt)]
pub fn derive_try_from_num(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input_token as DeriveInput);
expand_derive_try_from_num(input).into()
}
fn expand_derive_try_from_num(input: DeriveInput) -> TokenStream {
let attrs = input.attrs;
let ident = input.ident;
let generics = input.generics;
if let Data::Enum(data_enum) = input.data {
impl_try_from(data_enum, attrs, generics, ident)
} else {
panic!("cannot derive TryFromInt for structs or union.")
}
}
fn impl_try_from(
data_enum: DataEnum,
attrs: Vec<Attribute>,
generics: Generics,
ident: Ident,
) -> TokenStream {
let valid_repr = if let Some(valid_repr) = has_valid_repr(attrs) {
format_ident!("{}", valid_repr)
} else {
panic!(
"{} does not have invalid repr to implement TryFromInt.",
ident
);
};
for variant in &data_enum.variants {
if variant.discriminant.is_none() {
panic!("Enum can only have fields like Variant=1");
}
}
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
let fn_body = fn_body_tokens(VALUE_NAME, &data_enum, ident.clone());
let param = format_ident!("{}", VALUE_NAME);
quote!(
#[automatically_derived]
impl #impl_generics ::core::convert::TryFrom<#valid_repr> #type_generics for #ident #where_clause {
type Error = ::int_to_c_enum::TryFromIntError;
fn try_from(#param: #valid_repr) -> ::core::result::Result<Self, Self::Error> {
#fn_body
}
}
)
}
fn fn_body_tokens(value_name: &str, data_enum: &DataEnum, ident: Ident) -> TokenStream {
let mut match_bodys = quote!();
for variant in &data_enum.variants {
let (_, value) = variant
.discriminant
.as_ref()
.expect("Each field must be assigned a discriminant value explicitly");
let vairant_ident = &variant.ident;
let statement = quote!(#value => ::core::result::Result::Ok(#ident::#vairant_ident),);
match_bodys.append_all(statement);
}
match_bodys.append_all(
quote!(_ => core::result::Result::Err(::int_to_c_enum::TryFromIntError::InvalidValue),),
);
let param = format_ident!("{}", value_name);
quote!(match #param {
#match_bodys
})
}
fn has_valid_repr(attrs: Vec<Attribute>) -> Option<&'static str> {
for attr in attrs {
if let Some(repr) = parse_repr(attr) {
return Some(repr);
}
}
None
}
fn parse_repr(attr: Attribute) -> Option<&'static str> {
if !attr.path().is_ident(REPR_PATH) {
return None;
}
let mut repr = None;
attr.parse_nested_meta(|meta| {
for allowed_repr in ALLOWED_REPRS {
if meta.path.is_ident(*allowed_repr) {
repr = Some(*allowed_repr);
break;
}
}
Ok(())
})
.ok()?;
repr
}

View File

@ -0,0 +1,49 @@
// SPDX-License-Identifier: MPL-2.0
//! This crate provides a derive macro named TryFromInt. This macro can be used to automatically implement TryFrom trait
//! for [C-like enums](https://doc.rust-lang.org/stable/rust-by-example/custom_types/enum/c_like.html).
//!
//! Currently, this macro only supports enums with [explicit discriminants](https://doc.rust-lang.org/reference/items/enumerations.html#explicit-discriminants).
//!
//! Below is a simple example. We derive macro `TryFromInt` for an enum `Color`.
//! ```rust
//! use int_to_c_enum::TryFromInt;
//! #[repr(u8)]
//! #[derive(TryFromInt, Eq, PartialEq)]
//! pub enum Color {
//! Red = 1,
//! Yellow = 2,
//! Blue = 3,
//! }
//! // Then, we can use method `try_from` for `Color`.
//! let color = Color::try_from(1).unwrap();
//! assert!(color == Color::Red);
//! ```
//!
//! The `TryFromInt` macro will automatically implement trait `TryFrom<u8>` for `Color`.
//! After macro expansion, the generated code looks like as follows:
//! ```ignore
//! impl TryFrom<u8> for Color {
//! type Error = TryFromIntError;
//! fn try_from(value: u8) -> Result<Self, Self::Error> {
//! match value {
//! 1 => Ok(Color::Red),
//! 2 => Ok(Color::Yellow),
//! 3 => Ok(Color::Blue),
//! _ => Err(TryFromIntError::InvalidValue),
//! }
//! }
//! }
//! ```
//!
#![cfg_attr(not(test), no_std)]
/// Error type for TryFromInt derive macro
#[derive(Debug, Clone, Copy)]
pub enum TryFromIntError {
InvalidValue,
}
#[cfg(feature = "derive")]
pub use int_to_c_enum_derive::TryFromInt;

View File

@ -0,0 +1,24 @@
// SPDX-License-Identifier: MPL-2.0
use int_to_c_enum::TryFromInt;
#[derive(TryFromInt, Debug, PartialEq, Eq)]
#[repr(u8)]
enum Color {
Red = 1,
Blue = 2,
Green = 3,
}
#[test]
fn conversion() {
let color = Color::try_from(1).unwrap();
println!("color = {color:?}");
assert!(color == Color::Red);
}
#[test]
fn invalid_value() {
let color = Color::try_from(4);
assert!(color.is_err());
}