summaryrefslogtreecommitdiff
path: root/rust/macros/lib.rs
diff options
context:
space:
mode:
authorGary Guo <gary@garyguo.net>2022-11-10 19:41:18 +0300
committerMiguel Ojeda <ojeda@kernel.org>2022-12-04 03:59:15 +0300
commitb44becc5ee808e02bbda0f90ee0584f206693a33 (patch)
tree88c3ec578019f9a208d9a6251066d136eae97fe6 /rust/macros/lib.rs
parent60f18c225f5f6939e348c4b067711d10afd33151 (diff)
downloadlinux-b44becc5ee808e02bbda0f90ee0584f206693a33.tar.xz
rust: macros: add `#[vtable]` proc macro
This procedural macro attribute provides a simple way to declare a trait with a set of operations that later users can partially implement, providing compile-time `HAS_*` boolean associated constants that indicate whether a particular operation was overridden. This is useful as the Rust counterpart to structs like `file_operations` where some pointers may be `NULL`, indicating an operation is not provided. For instance: #[vtable] trait Operations { fn read(...) -> Result<usize> { Err(EINVAL) } fn write(...) -> Result<usize> { Err(EINVAL) } } #[vtable] impl Operations for S { fn read(...) -> Result<usize> { ... } } assert_eq!(<S as Operations>::HAS_READ, true); assert_eq!(<S as Operations>::HAS_WRITE, false); Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Sergio González Collado <sergio.collado@gmail.com> [Reworded, adapted for upstream and applied latest changes] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'rust/macros/lib.rs')
-rw-r--r--rust/macros/lib.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 15555e7ff487..e40caaf0a656 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -5,6 +5,7 @@
mod concat_idents;
mod helpers;
mod module;
+mod vtable;
use proc_macro::TokenStream;
@@ -72,6 +73,57 @@ pub fn module(ts: TokenStream) -> TokenStream {
module::module(ts)
}
+/// Declares or implements a vtable trait.
+///
+/// Linux's use of pure vtables is very close to Rust traits, but they differ
+/// in how unimplemented functions are represented. In Rust, traits can provide
+/// default implementation for all non-required methods (and the default
+/// implementation could just return `Error::EINVAL`); Linux typically use C
+/// `NULL` pointers to represent these functions.
+///
+/// This attribute is intended to close the gap. Traits can be declared and
+/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
+/// will be generated for each method in the trait, indicating if the implementor
+/// has overridden a method.
+///
+/// This attribute is not needed if all methods are required.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// // Declares a `#[vtable]` trait
+/// #[vtable]
+/// pub trait Operations: Send + Sync + Sized {
+/// fn foo(&self) -> Result<()> {
+/// Err(EINVAL)
+/// }
+///
+/// fn bar(&self) -> Result<()> {
+/// Err(EINVAL)
+/// }
+/// }
+///
+/// struct Foo;
+///
+/// // Implements the `#[vtable]` trait
+/// #[vtable]
+/// impl Operations for Foo {
+/// fn foo(&self) -> Result<()> {
+/// # Err(EINVAL)
+/// // ...
+/// }
+/// }
+///
+/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
+/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
+/// ```
+#[proc_macro_attribute]
+pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
+ vtable::vtable(attr, ts)
+}
+
/// Concatenate two identifiers.
///
/// This is useful in macros that need to declare or reference items with names