summaryrefslogtreecommitdiffstats
path: root/rust/macros/vtable.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
commitf4cdf7ca9a1fdcca413157df19753f388a5a224e (patch)
tree60a31895b2446cd7fa27514e8c2843534a0de0da /rust/macros/vtable.rs
downloadlinux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.tar.gz
linux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.zip
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-mediagrafted
Pull media updates from Mauro Carvalho Chehab: - v4l2-core: added ISP statistics support and per-block validation - v4l2-core: Allow unknown HDR10 white point and luminance - New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor - New codec: Milos: VPU v2.0 codec support - isp driver: gained support for Dreamchip RPPX1 ISP framework - vsp1 driver: gained support for RZ/T2H and RZ/N2H - Novalake driver: gained CVS support for new NVL hardware - dvb-core: fix feed leak on failed DMX_ADD_PID - several driver fixes, cleanups and minor improvements * tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits) media: ipu-bridge: check all DMI entries when overriding sensor rotation media: v4l2-async: avoid deleting unlinked ASC entry on link error media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement media: intel/ipu6: fix async notifier cleanup leak on parse error media: staging/ipu7: fix async notifier UAF on probe error path media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem() media: rcar-isp: Fix VSPX reference leaks media: rcar-isp: Release ISPCORE resources media: i2c: imx415: Release runtime PM reference on VBLANK error media: i2c: imx415: Return test pattern write errors media: renesas: vsp1: Declare index variables in for loop statement media: renesas: vsp1: Make reset control optional to support platforms without a reset line media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs media: nxp: imx8-isi: Add additional 32-bit RGB format support media: nxp: imx8-isi: Add 16-bit raw Bayer format support media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks media: nxp: imx8-isi: Correct color map between V4L2 and ISI ...
Diffstat (limited to 'rust/macros/vtable.rs')
-rw-r--r--rust/macros/vtable.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
new file mode 100644
index 000000000..be9a5ed8a
--- /dev/null
+++ b/rust/macros/vtable.rs
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use std::{
+ collections::HashSet,
+ iter::Extend, //
+};
+
+use proc_macro2::{
+ Ident,
+ TokenStream, //
+};
+use quote::ToTokens;
+use syn::{
+ parse_quote,
+ Error,
+ ImplItem,
+ Item,
+ ItemImpl,
+ ItemTrait,
+ Result,
+ TraitItem, //
+};
+
+fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
+ let mut gen_items = Vec::new();
+
+ gen_items.push(parse_quote! {
+ /// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable)
+ /// attribute when implementing this trait.
+ const USE_VTABLE_ATTR: ();
+ });
+
+ // Add `type OwnerModule: ModuleMetadata` as a required associated type if
+ // the trait does not already define it.
+ if !item
+ .items
+ .iter()
+ .any(|i| matches!(i, TraitItem::Type(t) if t.ident == "OwnerModule"))
+ {
+ gen_items.push(parse_quote! {
+ /// The module implementing this vtable trait.
+ ///
+ /// Automatically set to `crate::LocalModule` by the `#[vtable]`
+ /// impl macro.
+ type OwnerModule: ::kernel::ModuleMetadata;
+ });
+ }
+
+ for item in &item.items {
+ if let TraitItem::Fn(fn_item) = item {
+ let name = &fn_item.sig.ident;
+ let gen_const_name = Ident::new(
+ &format!("HAS_{}", name.to_string().to_uppercase()),
+ name.span(),
+ );
+
+ // We don't know on the implementation-site whether a method is required or provided
+ // so we have to generate a const for all methods.
+ let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs);
+ let comment =
+ format!("Indicates if the `{name}` method is overridden by the implementor.");
+ gen_items.push(parse_quote! {
+ #(#cfg_attrs)*
+ #[doc = #comment]
+ const #gen_const_name: bool = false;
+ });
+ }
+ }
+
+ item.items.extend(gen_items);
+ Ok(item)
+}
+
+fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
+ let mut gen_items = Vec::new();
+ let mut defined_items = HashSet::new();
+
+ // Iterate over all user-defined items to gather any possible explicit overrides.
+ for item in &item.items {
+ match item {
+ ImplItem::Const(const_item) => {
+ defined_items.insert(const_item.ident.clone());
+ }
+ ImplItem::Type(type_item) => {
+ defined_items.insert(type_item.ident.clone());
+ }
+ _ => {}
+ }
+ }
+
+ gen_items.push(parse_quote! {
+ const USE_VTABLE_ATTR: () = ();
+ });
+
+ // Auto-insert `type OwnerModule = crate::LocalModule` if not explicitly defined.
+ // `crate::LocalModule` resolves to the real module type (via `module!`) or a
+ // dummy fallback in non-module contexts (e.g., doctests).
+ if !defined_items.contains(&parse_quote!(OwnerModule)) {
+ gen_items.push(parse_quote! {
+ type OwnerModule = crate::LocalModule;
+ });
+ }
+
+ for item in &item.items {
+ if let ImplItem::Fn(fn_item) = item {
+ let name = &fn_item.sig.ident;
+ let gen_const_name = Ident::new(
+ &format!("HAS_{}", name.to_string().to_uppercase()),
+ name.span(),
+ );
+ // Skip if it's declared already -- this allows user override.
+ if defined_items.contains(&gen_const_name) {
+ continue;
+ }
+ let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs);
+ gen_items.push(parse_quote! {
+ #(#cfg_attrs)*
+ const #gen_const_name: bool = true;
+ });
+ }
+ }
+
+ item.items.extend(gen_items);
+ Ok(item)
+}
+
+pub(crate) fn vtable(input: Item) -> Result<TokenStream> {
+ match input {
+ Item::Trait(item) => Ok(handle_trait(item)?.into_token_stream()),
+ Item::Impl(item) => Ok(handle_impl(item)?.into_token_stream()),
+ _ => Err(Error::new_spanned(
+ input,
+ "`#[vtable]` attribute should only be applied to trait or impl block",
+ ))?,
+ }
+}