Sfoglia il codice sorgente

macro: generate RustSBI for struct with generics

Signed-off-by: Zhouqi Jiang <luojia@hust.edu.cn>
Zhouqi Jiang 1 anno fa
parent
commit
ccc0986b38
4 ha cambiato i file con 159 aggiunte e 4 eliminazioni
  1. 5 4
      macros/src/lib.rs
  2. 26 0
      src/lib.rs
  3. 22 0
      src/traits.rs
  4. 106 0
      tests/build-generics.rs

+ 5 - 4
macros/src/lib.rs

@@ -1,6 +1,6 @@
 use proc_macro::TokenStream;
 use quote::quote;
-use syn::{parse_macro_input, punctuated::Punctuated, Data, DeriveInput, Fields, Ident};
+use syn::{parse_macro_input, punctuated::Punctuated, Data, DeriveInput, Fields, Generics, Ident};
 
 #[derive(Clone, Default)]
 struct RustSBIImp<'a> {
@@ -63,11 +63,11 @@ pub fn derive_rustsbi(input: TokenStream) -> TokenStream {
     }
 
     let mut ans = TokenStream::new();
-    ans.extend(impl_derive_rustsbi(&input.ident, imp));
+    ans.extend(impl_derive_rustsbi(&input.ident, imp, &input.generics));
     ans
 }
 
-fn impl_derive_rustsbi(name: &Ident, imp: RustSBIImp) -> TokenStream {
+fn impl_derive_rustsbi(name: &Ident, imp: RustSBIImp, generics: &Generics) -> TokenStream {
     let base_probe: usize = 1;
     let fence_probe: usize = if imp.fence.is_some() { 1 } else { 0 };
     let hsm_probe: usize = if imp.hsm.is_some() { 1 } else { 0 };
@@ -193,8 +193,9 @@ fn impl_derive_rustsbi(name: &Ident, imp: RustSBIImp) -> TokenStream {
     } else {
         quote! {}
     };
+    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
     let gen = quote! {
-    impl rustsbi::RustSBI for #name {
+    impl #impl_generics rustsbi::RustSBI for #name #ty_generics #where_clause {
         #[inline]
         fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> ::rustsbi::spec::binary::SbiRet {
             match extension {

+ 26 - 0
src/lib.rs

@@ -801,6 +801,32 @@ pub extern crate sbi_spec as spec;
 /// # }
 /// ```
 ///
+/// The struct as derive input may include generics, specifically type generics, lifetimes,
+/// constant generics and where clauses.
+///
+/// ```rust
+/// #[derive(RustSBI)]
+/// struct MySBI<'a, T: rustsbi::Fence> {
+///     fence: T,
+///     info: &'a MyEnvInfo,
+/// }
+///
+/// # use rustsbi::{RustSBI, HartMask};
+/// # use sbi_spec::binary::SbiRet;
+/// # struct MyFence;
+/// # impl rustsbi::Fence for MyFence {
+/// #     fn remote_fence_i(&self, _: HartMask) -> SbiRet { unimplemented!() }
+/// #     fn remote_sfence_vma(&self, _: HartMask, _: usize, _: usize) -> SbiRet { unimplemented!() }
+/// #     fn remote_sfence_vma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet { unimplemented!() }
+/// # }
+/// # struct MyEnvInfo;
+/// # impl rustsbi::EnvInfo for MyEnvInfo {
+/// #     fn mvendorid(&self) -> usize { 1 }
+/// #     fn marchid(&self) -> usize { 2 }
+/// #     fn mimpid(&self) -> usize { 3 }
+/// # }
+/// ```
+///
 /// # Notes
 // note: following documents are inherted from `RustSBI` in the `rustsbi_macros` package.
 #[doc(inline)]

+ 22 - 0
src/traits.rs

@@ -9,6 +9,13 @@ pub trait RustSBI {
     fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet;
 }
 
+impl<T: RustSBI> RustSBI for &T {
+    #[inline(always)]
+    fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
+        <T as RustSBI>::handle_ecall(self, extension, function, param)
+    }
+}
+
 /// Machine environment information.
 ///
 /// This trait is useful to build an SBI environment when RustSBI is not run directly on RISC-V machine mode.
@@ -27,6 +34,21 @@ pub trait EnvInfo {
     fn mimpid(&self) -> usize;
 }
 
+impl<T: EnvInfo> EnvInfo for &T {
+    #[inline(always)]
+    fn mvendorid(&self) -> usize {
+        <T as EnvInfo>::mvendorid(self)
+    }
+    #[inline(always)]
+    fn marchid(&self) -> usize {
+        <T as EnvInfo>::marchid(self)
+    }
+    #[inline(always)]
+    fn mimpid(&self) -> usize {
+        <T as EnvInfo>::mimpid(self)
+    }
+}
+
 // Macro internal structures and functions.
 // DO NOT USE code here directly; use derive macro #[derive(RustSBI)] instead.
 

+ 106 - 0
tests/build-generics.rs

@@ -0,0 +1,106 @@
+use rustsbi::RustSBI;
+use sbi_spec::binary::SbiRet;
+
+// These structs should pass Rust build.
+
+#[derive(RustSBI)]
+struct WithGenerics<T: rustsbi::Timer> {
+    reset: DummyReset,
+    timer: T,
+    info: DummyEnvInfo,
+}
+
+#[derive(RustSBI)]
+struct WithWhereClause<T>
+where
+    T: rustsbi::Timer,
+{
+    reset: DummyReset,
+    timer: T,
+    info: DummyEnvInfo,
+}
+
+#[derive(RustSBI)]
+struct WithConstantGenerics<const N: usize> {
+    info: DummyEnvInfo,
+    _dummy: [u8; N],
+}
+
+#[derive(RustSBI)]
+struct WithLifetime<'a> {
+    info: &'a DummyEnvInfo,
+}
+
+#[derive(RustSBI)]
+struct WithEverythingCombined<'a, T: rustsbi::Timer, U, const N: usize>
+where
+    U: rustsbi::Reset,
+{
+    timer: T,
+    reset: U,
+    info: &'a DummyEnvInfo,
+    _dummy: [u8; N],
+}
+
+#[test]
+fn test_impl_id() {
+    let sbi = WithGenerics {
+        reset: DummyReset,
+        timer: DummyTimer,
+        info: DummyEnvInfo,
+    };
+    assert_eq!(sbi.handle_ecall(0x10, 0x1, [0; 6]).value, 4);
+    let sbi = WithWhereClause {
+        reset: DummyReset,
+        timer: DummyTimer,
+        info: DummyEnvInfo,
+    };
+    assert_eq!(sbi.handle_ecall(0x10, 0x1, [0; 6]).value, 4);
+    let sbi = WithConstantGenerics {
+        info: DummyEnvInfo,
+        _dummy: [0; 100],
+    };
+    assert_eq!(sbi.handle_ecall(0x10, 0x1, [0; 6]).value, 4);
+    let dummy_info = DummyEnvInfo;
+    let sbi = WithLifetime { info: &dummy_info };
+    assert_eq!(sbi.handle_ecall(0x10, 0x1, [0; 6]).value, 4);
+    let sbi = WithEverythingCombined {
+        timer: DummyTimer,
+        reset: DummyReset,
+        info: &dummy_info,
+        _dummy: [0; 10],
+    };
+    assert_eq!(sbi.handle_ecall(0x10, 0x1, [0; 6]).value, 4);
+}
+
+struct DummyReset;
+
+impl rustsbi::Reset for DummyReset {
+    fn system_reset(&self, _: u32, _: u32) -> SbiRet {
+        unimplemented!()
+    }
+}
+
+struct DummyTimer;
+
+impl rustsbi::Timer for DummyTimer {
+    fn set_timer(&self, _: u64) {
+        unimplemented!()
+    }
+}
+
+struct DummyEnvInfo;
+
+impl rustsbi::EnvInfo for DummyEnvInfo {
+    fn mvendorid(&self) -> usize {
+        unimplemented!()
+    }
+
+    fn marchid(&self) -> usize {
+        unimplemented!()
+    }
+
+    fn mimpid(&self) -> usize {
+        unimplemented!()
+    }
+}