Message ID | 20231026201855.1497680-1-benno.lossin@proton.me |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:d641:0:b0:403:3b70:6f57 with SMTP id cy1csp146802vqb; Thu, 26 Oct 2023 13:20:19 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHWgU66iDvwFlzaKgnFyfZJt+wkG/2OBA+SGFIho98OSNYGwkoQEA+xQbswJGrvK2pSXKNG X-Received: by 2002:a25:aa85:0:b0:d9a:5244:32e5 with SMTP id t5-20020a25aa85000000b00d9a524432e5mr496477ybi.35.1698351618523; Thu, 26 Oct 2023 13:20:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698351618; cv=none; d=google.com; s=arc-20160816; b=nj+LCysv/CKEQvjzmy3bYVJmM8ZWKNaOqO8e0Ytd+5PUi+vJ0bcLJDgfYADd+jhEF0 oBI89enKVENsv5cvvweIaD/PAUJ76fa1m9JdQHNW3lkapJUrytuQEbdQhGtKrBrvNfMH OhknySNYRrno6ofQCv9fryS+p3kpb447gs0KkPJb8/H1dagwkc7k2qU5b4iMAb6zlsCR EKiiqJaJNJkRlzBR+mDDphP3eCJdYSxaco21ykCRup0pNZBadyIrFQznOARiR0ZlV6sB sm7X3INUDvpEOhwMXyDYUKHsxHfNDbaJbCxgbOPfcmgwafjlep40OQXEKeAEZtjsoNIH cVRg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:message-id:subject:cc:from:to:date:dkim-signature; bh=MY6UhJS4wgOAoosPta+TuxtbXCsYhD59Xf2pfqIYj2s=; fh=K2zC0Msoiy06E4CYiPNDVqlwL4plEPYi662pDdRabLM=; b=k4hPA+K+8Mbyjxn1NM2Tq/zdsdZhlVrSI0cTn94njepaMY1E+bIO0sgO602WGTT/8G U5HBwja3MKPEk9Qxcpdh7KssDmaWCCwQ15u+GPR4C6RFncuO4tiSlfG6AY3AzJ734fwj WjjfaTlsTn9NV3jc5yit1RerKiI4p9fYSBswxWwSvX0gE2OXpZ8lgG1xKydVFqMDrp1a ohn2+91wZQ8nPiCgQcJcG2ySWfNsEJxbuvxLRfOSIozviclkpW7nUPaxAA/WxMLQHJTt dLSgwDEvlXoRvXiunqPzsPboeNw7GKEMDyxjjDBJ2XhiW6951RvHijWYxgzPpNnCPH3V 7E+g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=dGbPzAOc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from agentk.vger.email (agentk.vger.email. [2620:137:e000::3:2]) by mx.google.com with ESMTPS id k138-20020a252490000000b00d81755db936si223174ybk.240.2023.10.26.13.20.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Oct 2023 13:20:18 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) client-ip=2620:137:e000::3:2; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=dGbPzAOc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id EA4E281C00DA; Thu, 26 Oct 2023 13:20:14 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344818AbjJZUUA (ORCPT <rfc822;aposhian.dev@gmail.com> + 26 others); Thu, 26 Oct 2023 16:20:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55514 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231971AbjJZUT7 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 26 Oct 2023 16:19:59 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6DEC31AC for <linux-kernel@vger.kernel.org>; Thu, 26 Oct 2023 13:19:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1698351593; x=1698610793; bh=MY6UhJS4wgOAoosPta+TuxtbXCsYhD59Xf2pfqIYj2s=; h=Date:To:From:Cc:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=dGbPzAOcCpW+TbJACsMXT18aTk1rLFR5+rb05l3gHLPdhgtMrVbqZVRZ50zxXpY2o B7mIbgbT0foKPJ/yVeAjyepHdQbl8FwlcawjHZ3G9k940FIvLuXSVKIGt+Ya41Rnfl hclu30YXG9ikEA3d98cRg+N9ZFlE5ULWNGl/2Azr+CspZVqq8ncu3jmlU4DsNHvc4B sDvr5sJzuAsXe2dfSTsitxxpvm5+FVKPGITNVgASvMAjGcl5v/UdRYDj16Yh2FESpP Jh3bz3+/HbJvj674iAU5dmrPCQEUJlRyWlHFFGEl+TWqTpxsOiSXaX52w9YrVY40lo uJwBTi5C/5K7g== Date: Thu, 26 Oct 2023 20:19:33 +0000 To: Miguel Ojeda <ojeda@kernel.org>, Wedson Almeida Filho <wedsonaf@gmail.com>, Alex Gaynor <alex.gaynor@gmail.com>, Boqun Feng <boqun.feng@gmail.com>, Gary Guo <gary@garyguo.net>, =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= <bjorn3_gh@protonmail.com>, Benno Lossin <benno.lossin@proton.me>, Andreas Hindborg <a.hindborg@samsung.com>, Alice Ryhl <aliceryhl@google.com>, Martin Rodriguez Reboredo <yakoyoku@gmail.com>, Asahi Lina <lina@asahilina.net>, Sven Van Asbroeck <thesven73@gmail.com>, Viktor Garske <viktor@v-gar.de>, Finn Behrens <me@kloenk.dev> From: Benno Lossin <benno.lossin@proton.me> Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3] rust: macros: improve `#[vtable]` documentation Message-ID: <20231026201855.1497680-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Thu, 26 Oct 2023 13:20:15 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1780850746513897197 X-GMAIL-MSGID: 1780850746513897197 |
Series |
[v3] rust: macros: improve `#[vtable]` documentation
|
|
Commit Message
Benno Lossin
Oct. 26, 2023, 8:19 p.m. UTC
Traits marked with `#[vtable]` need to provide default implementations
for optional functions. The C side represents these with `NULL` in the
vtable, so the default functions are never actually called. We do not
want to replicate the default behavior from C in Rust, because that is
not maintainable. Therefore we should use `build_error` in those default
implementations. The error message for that is provided at
`kernel::error::VTABLE_DEFAULT_ERROR`.
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
- don't hide the import of the constant in the example
- fixed "function" typo
- improve paragraph about optional functions
- do not remove the `Send + Sync + Sized` bounds on the example
v1 -> v2:
- removed imperative mode in the paragraph describing optional
functions.
rust/kernel/error.rs | 4 ++++
rust/macros/lib.rs | 37 ++++++++++++++++++++++++++++++-------
2 files changed, 34 insertions(+), 7 deletions(-)
base-commit: 3857af38e57a80b15b994e19d1f4301cac796481
Comments
On 23/10/26 08:19PM, Benno Lossin wrote: > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > v2 -> v3: > - don't hide the import of the constant in the example > - fixed "function" typo > - improve paragraph about optional functions > - do not remove the `Send + Sync + Sized` bounds on the example > > v1 -> v2: > - removed imperative mode in the paragraph describing optional > functions. > > rust/kernel/error.rs | 4 ++++ > rust/macros/lib.rs | 37 ++++++++++++++++++++++++++++++------- > 2 files changed, 34 insertions(+), 7 deletions(-) > > diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs > index 05fcab6abfe6..1373cde025ef 100644 > --- a/rust/kernel/error.rs > +++ b/rust/kernel/error.rs > @@ -335,3 +335,7 @@ pub(crate) fn from_result<T, F>(f: F) -> T > Err(e) => T::from(e.to_errno() as i16), > } > } > + > +/// Error message for calling a default function of a [`#[vtable]`](macros::vtable) trait. > +pub const VTABLE_DEFAULT_ERROR: &str = > + "This function must not be called, see the #[vtable] documentation."; > diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs > index c42105c2ff96..917a51183c23 100644 > --- a/rust/macros/lib.rs > +++ b/rust/macros/lib.rs > @@ -87,27 +87,48 @@ pub fn module(ts: TokenStream) -> TokenStream { > /// 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 closes that gap. A trait can be annotated with the `#[vtable]` attribute. > +/// Implementers of the trait will then also have to annotate the trait with `#[vtable]`. This > +/// attribute generates a `HAS_*` associated constant bool for each method in the trait that is set > +/// to true if the implementer has overridden the associated method. The above paragraph seems to be wrapped at 100 characters while the paragraph below seems to be wrapped at 80 characters. Cheers, Ariel > +/// > +/// For a trait method to be optional, it must have a default implementation. > /// This is also the case for traits annotated with `#[vtable]`, but in this > +/// case the default implementation will never be executed. The reason for this > +/// is that the functions will be called through function pointers installed in > +/// C side vtables. When an optional method is not implemented on a `#[vtable]` > +/// trait, a NULL entry is installed in the vtable. Thus the default > +/// implementation is never called. Since these traits are not designed to be > +/// used on the Rust side, it should not be possible to call the default > +/// implementation. This is done to ensure that we call the vtable methods > +/// through the C vtable, and not through the Rust vtable. Therefore, the > +/// default implementation should call `kernel::build_error`, which prevents > +/// calls to this function at compile time: > +/// > +/// ```compile_fail > +/// # use kernel::error::VTABLE_DEFAULT_ERROR; > +/// kernel::build_error(VTABLE_DEFAULT_ERROR) > +/// ``` > +/// > +/// note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`]. > /// > -/// This attribute is not needed if all methods are required. > +/// This macro should not be used when all functions are required. > /// > /// # Examples > /// > /// ```ignore > +/// use kernel::error::VTABLE_DEFAULT_ERROR; > /// use kernel::prelude::*; > /// > /// // Declares a `#[vtable]` trait > /// #[vtable] > /// pub trait Operations: Send + Sync + Sized { > /// fn foo(&self) -> Result<()> { > -/// Err(EINVAL) > +/// kernel::build_error(VTABLE_DEFAULT_ERROR) > /// } > /// > /// fn bar(&self) -> Result<()> { > -/// Err(EINVAL) > +/// kernel::build_error(VTABLE_DEFAULT_ERROR) > /// } > /// } > /// > @@ -125,6 +146,8 @@ pub fn module(ts: TokenStream) -> TokenStream { > /// assert_eq!(<Foo as Operations>::HAS_FOO, true); > /// assert_eq!(<Foo as Operations>::HAS_BAR, false); > /// ``` > +/// > +/// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html > #[proc_macro_attribute] > pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { > vtable::vtable(attr, ts) > > base-commit: 3857af38e57a80b15b994e19d1f4301cac796481 > -- > 2.41.0 > >
On 10/26/23 17:19, Benno Lossin wrote: > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > v2 -> v3: > - don't hide the import of the constant in the example > - fixed "function" typo > - improve paragraph about optional functions > - do not remove the `Send + Sync + Sized` bounds on the example > > v1 -> v2: > - removed imperative mode in the paragraph describing optional > functions. > > [...] Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On 26 Oct 2023, at 22:19, Benno Lossin wrote: > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs > index c42105c2ff96..917a51183c23 100644 > --- a/rust/macros/lib.rs > +++ b/rust/macros/lib.rs > @@ -87,27 +87,48 @@ pub fn module(ts: TokenStream) -> TokenStream { > /// 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 closes that gap. A trait can be annotated with the `#[vtable]` attribute. > +/// Implementers of the trait will then also have to annotate the trait with `#[vtable]`. This > +/// attribute generates a `HAS_*` associated constant bool for each method in the trait that is set > +/// to true if the implementer has overridden the associated method. > +/// > +/// For a trait method to be optional, it must have a default implementation. > +/// This is also the case for traits annotated with `#[vtable]`, but in this > +/// case the default implementation will never be executed. The reason for this > +/// is that the functions will be called through function pointers installed in > +/// C side vtables. When an optional method is not implemented on a `#[vtable]` > +/// trait, a NULL entry is installed in the vtable. Thus the default > +/// implementation is never called. Since these traits are not designed to be > +/// used on the Rust side, it should not be possible to call the default > +/// implementation. This is done to ensure that we call the vtable methods > +/// through the C vtable, and not through the Rust vtable. Therefore, the > +/// default implementation should call `kernel::build_error`, which prevents > +/// calls to this function at compile time: In the future it would be nice to have something like `#[default]` or `#[optional]` to automatically derive the implementation. > +/// > +/// ```compile_fail > +/// # use kernel::error::VTABLE_DEFAULT_ERROR; > +/// kernel::build_error(VTABLE_DEFAULT_ERROR) > +/// ``` > +/// > +/// note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`]. > /// > -/// This attribute is not needed if all methods are required. > +/// This macro should not be used when all functions are required. Reviewed-by: Finn Behrens <me@kloenk.dev>
On 10/27/23 10:02, Finn Behrens wrote: > > > On 26 Oct 2023, at 22:19, Benno Lossin wrote: > >> Traits marked with `#[vtable]` need to provide default implementations >> for optional functions. The C side represents these with `NULL` in the >> vtable, so the default functions are never actually called. We do not >> want to replicate the default behavior from C in Rust, because that is >> not maintainable. Therefore we should use `build_error` in those default >> implementations. The error message for that is provided at >> `kernel::error::VTABLE_DEFAULT_ERROR`. >> >> Signed-off-by: Benno Lossin <benno.lossin@proton.me> >> --- >> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs >> index c42105c2ff96..917a51183c23 100644 >> --- a/rust/macros/lib.rs >> +++ b/rust/macros/lib.rs >> @@ -87,27 +87,48 @@ pub fn module(ts: TokenStream) -> TokenStream { >> /// 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 closes that gap. A trait can be annotated with the `#[vtable]` attribute. >> +/// Implementers of the trait will then also have to annotate the trait with `#[vtable]`. This >> +/// attribute generates a `HAS_*` associated constant bool for each method in the trait that is set >> +/// to true if the implementer has overridden the associated method. >> +/// >> +/// For a trait method to be optional, it must have a default implementation. >> +/// This is also the case for traits annotated with `#[vtable]`, but in this >> +/// case the default implementation will never be executed. The reason for this >> +/// is that the functions will be called through function pointers installed in >> +/// C side vtables. When an optional method is not implemented on a `#[vtable]` >> +/// trait, a NULL entry is installed in the vtable. Thus the default >> +/// implementation is never called. Since these traits are not designed to be >> +/// used on the Rust side, it should not be possible to call the default >> +/// implementation. This is done to ensure that we call the vtable methods >> +/// through the C vtable, and not through the Rust vtable. Therefore, the >> +/// default implementation should call `kernel::build_error`, which prevents >> +/// calls to this function at compile time: > In the future it would be nice to have something like `#[default]` or `#[optional]` to automatically derive the implementation. I brought this up in the discussion on zulip [1]. But Wedson argued that macros make it more magical and less easy to understand. So for the time being, I just wanted to improve the docs. [1]: https://rust-for-linux.zulipchat.com/#narrow/stream/288089-General/topic/.60bool.3A.3Athen.60.20helper/near/395659471
On 10/26/23 23:12, Ariel Miculas (amiculas) wrote: > On 23/10/26 08:19PM, Benno Lossin wrote: >> Traits marked with `#[vtable]` need to provide default implementations >> for optional functions. The C side represents these with `NULL` in the >> vtable, so the default functions are never actually called. We do not >> want to replicate the default behavior from C in Rust, because that is >> not maintainable. Therefore we should use `build_error` in those default >> implementations. The error message for that is provided at >> `kernel::error::VTABLE_DEFAULT_ERROR`. >> >> Signed-off-by: Benno Lossin <benno.lossin@proton.me> >> --- >> v2 -> v3: >> - don't hide the import of the constant in the example >> - fixed "function" typo >> - improve paragraph about optional functions >> - do not remove the `Send + Sync + Sized` bounds on the example >> >> v1 -> v2: >> - removed imperative mode in the paragraph describing optional >> functions. >> >> rust/kernel/error.rs | 4 ++++ >> rust/macros/lib.rs | 37 ++++++++++++++++++++++++++++++------- >> 2 files changed, 34 insertions(+), 7 deletions(-) >> >> diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs >> index 05fcab6abfe6..1373cde025ef 100644 >> --- a/rust/kernel/error.rs >> +++ b/rust/kernel/error.rs >> @@ -335,3 +335,7 @@ pub(crate) fn from_result<T, F>(f: F) -> T >> Err(e) => T::from(e.to_errno() as i16), >> } >> } >> + >> +/// Error message for calling a default function of a [`#[vtable]`](macros::vtable) trait. >> +pub const VTABLE_DEFAULT_ERROR: &str = >> + "This function must not be called, see the #[vtable] documentation."; >> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs >> index c42105c2ff96..917a51183c23 100644 >> --- a/rust/macros/lib.rs >> +++ b/rust/macros/lib.rs >> @@ -87,27 +87,48 @@ pub fn module(ts: TokenStream) -> TokenStream { >> /// 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 closes that gap. A trait can be annotated with the `#[vtable]` attribute. >> +/// Implementers of the trait will then also have to annotate the trait with `#[vtable]`. This >> +/// attribute generates a `HAS_*` associated constant bool for each method in the trait that is set >> +/// to true if the implementer has overridden the associated method. > > The above paragraph seems to be wrapped at 100 characters while the > paragraph below seems to be wrapped at 80 characters. Oh I forgot about that. Miguel, would it be reasonable for you to fix this when picking the patch?
On Fri, Oct 27, 2023 at 11:32 AM Benno Lossin <benno.lossin@proton.me> wrote: > > Oh I forgot about that. Miguel, would it be reasonable for you to fix > this when picking the patch? Yeah, no worries. Thanks! Cheers, Miguel
On 10/26/23 22:19, Benno Lossin wrote: > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Benno Lossin <benno.lossin@proton.me> writes: > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>
On Thu, Oct 26, 2023 at 10:20 PM Benno Lossin <benno.lossin@proton.me> wrote: > > Traits marked with `#[vtable]` need to provide default implementations > for optional functions. The C side represents these with `NULL` in the > vtable, so the default functions are never actually called. We do not > want to replicate the default behavior from C in Rust, because that is > not maintainable. Therefore we should use `build_error` in those default > implementations. The error message for that is provided at > `kernel::error::VTABLE_DEFAULT_ERROR`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Applied to `rust-next` (with the requested wrapping applied and capitalized sentence). Thanks everyone! Cheers, Miguel
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 05fcab6abfe6..1373cde025ef 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -335,3 +335,7 @@ pub(crate) fn from_result<T, F>(f: F) -> T Err(e) => T::from(e.to_errno() as i16), } } + +/// Error message for calling a default function of a [`#[vtable]`](macros::vtable) trait. +pub const VTABLE_DEFAULT_ERROR: &str = + "This function must not be called, see the #[vtable] documentation."; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index c42105c2ff96..917a51183c23 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -87,27 +87,48 @@ pub fn module(ts: TokenStream) -> TokenStream { /// 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 closes that gap. A trait can be annotated with the `#[vtable]` attribute. +/// Implementers of the trait will then also have to annotate the trait with `#[vtable]`. This +/// attribute generates a `HAS_*` associated constant bool for each method in the trait that is set +/// to true if the implementer has overridden the associated method. +/// +/// For a trait method to be optional, it must have a default implementation. +/// This is also the case for traits annotated with `#[vtable]`, but in this +/// case the default implementation will never be executed. The reason for this +/// is that the functions will be called through function pointers installed in +/// C side vtables. When an optional method is not implemented on a `#[vtable]` +/// trait, a NULL entry is installed in the vtable. Thus the default +/// implementation is never called. Since these traits are not designed to be +/// used on the Rust side, it should not be possible to call the default +/// implementation. This is done to ensure that we call the vtable methods +/// through the C vtable, and not through the Rust vtable. Therefore, the +/// default implementation should call `kernel::build_error`, which prevents +/// calls to this function at compile time: +/// +/// ```compile_fail +/// # use kernel::error::VTABLE_DEFAULT_ERROR; +/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// ``` +/// +/// note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`]. /// -/// This attribute is not needed if all methods are required. +/// This macro should not be used when all functions are required. /// /// # Examples /// /// ```ignore +/// use kernel::error::VTABLE_DEFAULT_ERROR; /// use kernel::prelude::*; /// /// // Declares a `#[vtable]` trait /// #[vtable] /// pub trait Operations: Send + Sync + Sized { /// fn foo(&self) -> Result<()> { -/// Err(EINVAL) +/// kernel::build_error(VTABLE_DEFAULT_ERROR) /// } /// /// fn bar(&self) -> Result<()> { -/// Err(EINVAL) +/// kernel::build_error(VTABLE_DEFAULT_ERROR) /// } /// } /// @@ -125,6 +146,8 @@ pub fn module(ts: TokenStream) -> TokenStream { /// assert_eq!(<Foo as Operations>::HAS_FOO, true); /// assert_eq!(<Foo as Operations>::HAS_BAR, false); /// ``` +/// +/// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html #[proc_macro_attribute] pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { vtable::vtable(attr, ts)