Re: [PATCH v8 03/12] rust: num: add cv! macro to create values from constant expressions

"Gary Guo" <[email protected]>
Newsgroups dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
On Thu Aug 27, 2026 at 2:48 PM BST, Eliot Courtney wrote:
> On Thu Aug 27, 2026 at 8:12 PM JST, Alexandre Courbot wrote:
>> On Thu Aug 27, 2026 at 7:42 PM JST, Alexandre Courbot wrote:
>>> On Thu Aug 27, 2026 at 6:32 PM JST, Alice Ryhl wrote:
>>>> On Thu, Aug 27, 2026 at 04:28:31PM +0900, Eliot Courtney wrote:
>>>>> Currently, using NonZero/Bounded constants is quite verbose. It's
>>>>> unfortunate because it disincentivizes using it in interface boundaries.
>>>>> Introduce a macro to make it nicer to use. The macro `cv!` (for constant
>>>>> value) takes a const integer expression and widens it to i128 (at build
>>>>> time only) before passing it as a const generic value to a new trait
>>>>> function `FromConst::from_const`. The trait is implemented by NonZero,
>>>>> Bounded, and Alignment and lets values of each be constructed from
>>>>> constants without a verbose turbofish syntax. For example,
>>>>> `const { NonZero::new(1).unwrap() }` can be written as `cv!(1)`.
>>>>> 
>>>>> Suggested-by: Gary Guo <[email protected]>
>>>>> Signed-off-by: Eliot Courtney <[email protected]>
>>>>
>>>> This doesn't work in const context, so I don't think this is a great
>>>> strategy.
>>>>
>>>> I would want to use it for cases like this:
>>>>
>>>> drivers/android/binder/netlink.rs
>>>>         const BINDER_CMD_REPORT: u8 = kernel::uapi::BINDER_CMD_REPORT as u8;
>>>>         const BINDER_A_REPORT_ERROR: c_int = kernel::uapi::BINDER_A_REPORT_ERROR as c_int;
>>>>         const BINDER_A_REPORT_CONTEXT: c_int = kernel::uapi::BINDER_A_REPORT_CONTEXT as c_int;
>>>>         const BINDER_A_REPORT_FROM_PID: c_int = kernel::uapi::BINDER_A_REPORT_FROM_PID as c_int;
>>>>         const BINDER_A_REPORT_FROM_TID: c_int = kernel::uapi::BINDER_A_REPORT_FROM_TID as c_int;
>>>>         const BINDER_A_REPORT_TO_PID: c_int = kernel::uapi::BINDER_A_REPORT_TO_PID as c_int;
>>>>         const BINDER_A_REPORT_TO_TID: c_int = kernel::uapi::BINDER_A_REPORT_TO_TID as c_int;
>>>>         const BINDER_A_REPORT_IS_REPLY: c_int = kernel::uapi::BINDER_A_REPORT_IS_REPLY as c_int;
>>>>         const BINDER_A_REPORT_FLAGS: c_int = kernel::uapi::BINDER_A_REPORT_FLAGS as c_int;
>>>>         const BINDER_A_REPORT_CODE: c_int = kernel::uapi::BINDER_A_REPORT_CODE as c_int;
>>>>         const BINDER_A_REPORT_DATA_SIZE: c_int = kernel::uapi::BINDER_A_REPORT_DATA_SIZE as c_int;
>>>
>>> `const_as!` [1] should do the trick for this, provided you don't need to
>>> create a const `NonZero`.
>>>
>>> [1] https://lore.kernel.org/all/[email protected]/
>>
>> ... but I agree it would be nice to be able to use this in const
>> context. And there is an overlap with `const_as!` that becomes more
>> obvious the more I look at it.
>>
>> In for a penny, in for a pound of macro code as they say. Since we
>> agreed on using macros, how about unifying both under the same `cv!`
>> macro, with as many branches as we have types we want to initialize from
>> a constant value? For instance:
>>
>>     // Does what `const_as!` currently does under the hood.
>>     const BINDER_CMD_REPORT: u8 = cv!(u8::from(kernel::uapi::BINDER_CMD_REPORT));
>>     // Calls `NonZero::new().unwrap()` under the hood.
>>     const SOME_NONZERO: NonZero<u8> = cv!(NonZero::new(kernel::uapi::NONZERO_VALUE));
>>     // Calls `Bounded::new::<{ ...}>()` under the hood.
>>     const SOME_BOUNDED: Bounded<u32, 2> = cv!(Bounded::new(kernel::uapi::SMALL_VALUE));
>>
>> I.e. we would have one extra matching arm in `cv!` per type it handles
>> instead of implementing a trait. The syntax of the macro would look more
>> natural (bye bye `const_as`'s awkward `=>`), albeit it would have the
>> limitations of such a semantic dispatch.
>>
>> Even the name `const_as!` wasn't really accurate to begin with: what it
>> really emulates is a const `try_from`, and we even discussed
>> implementing it in these terms in the future.
>>
>> I'm sure the idea needs more polishing but I think there's something to
>> explore here.
>
> Yeah I agree that const_as! is similar and if we had const traits we
> could fully merge them and have it always work in a const context for
> both duties (which are really a const tryfrom as you said).
>
> I am not sure about the suggested syntax (e.g.
> cv!(Bounded::new(kernel::uapi::SMALL_VALUE))), since it seems very
> verbose.
>
> Alternatively, what about just directly merging them so you use
> cv!(5) (the non const context FromConst::from_const dispatcher in this
> series) or cv!(value => u8) (exactly const_as!), with the =>
> distinguishing between the two?
>
> So this is what would work for Alice's example (const_as! but pushed
> inside cv!):
> ```
> const BINDER_CMD_REPORT: u8 = cv!(kernel::uapi::BINDER_CMD_REPORT => u8);
> ```
>
> When we have const traits then we could remove the => syntax I think.

It'd still be useful to allow explicit specification if user prefers. I think it
makes sense to (ultimately) translate

    cv!(val)

to

    const { FromConst::from_const(val as i128) }

and

    cv!(val => ty)

to

    const { ty::from_const(val as i128) }

I think there might be some tricks possible to get it working without const
trait, e.g. for `Bounded` and `Alignment` we could simply add an inherent method

    #[doc(hidden)]
    #[inline]
    const fn __from_const(val: i128) -> Self { ... }

but I'll need to think about how to make it work with core types.

Best,
Gary
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.