From: Daniel Almeida <daniel.almeida@collabora.com>
To: wedsonaf@gmail.com, ojeda@kernel.org, mchehab@kernel.org,
hverkuil@xs4all.nl
Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-media@vger.kernel.org, kernel@collabora.com
Subject: Re: [PATCH 0/6] Initial Rust V4L2 support
Date: Sat, 08 Apr 2023 16:06:31 -0300 [thread overview]
Message-ID: <0062de67bfe89653ffdc5e3c564fb24bc1adf3f4.camel@collabora.com> (raw)
In-Reply-To: <20230406215615.122099-1-daniel.almeida@collabora.com>
By the way, one of the things I dislike about this series is that
there's a needless distinction between
struct Foo(bindgen::foo)
vs
struct FooRef(*mut bindgen::foo)
This gets in the way of having an owned Foo embedded into a larger
struct. It also gets in the way of instantiating an owned Foo on the
stack.
My first thought was to use enums:
enum Foo {
Owned(bindgen::foo),
NotOwned(*mut bindgen::foo),
}
But that would mean that users would invariably pay the price for the
owned variant always, as enums use as much space as its largest
variant.
My current understanding is that we can move all the implementations to
traits, with a suitable bound on AsRef<bindings::foo> and
AsMut<bindings::foo>.
Here is a code example for the wrapper of bindings::v4l2_format (see
format.rs), which was extended to account for both owned and non-owned
bindgen types:
```
use core::cell::UnsafeCell;
/// The shared implementation between Format and FormatRef.
pub trait FormatImpl: AsRef<bindings::v4l2_format> +
AsMut<bindings::v4l2_format> {
/// Returns the `type_` field.
fn type_(&self) -> u32 {
self.as_ref().type_
}
/// Get the field `field` for the `pix` union member.
fn pix_field(&self) -> Result<enums::Field> {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
enums::Field::try_from(pix.field)
}
/// Get the field `width` for the `pix` union member.
fn pix_width(&self) -> u32 {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
pix.width
}
/// Get the field `height` for the `pix` union member.
fn pix_height(&self) -> u32 {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
pix.height
}
/// Get the field `pixelformat` for the `pix` union member.
fn pix_pixelformat(&self) -> u32 {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
pix.pixelformat
}
/// Get the field `bytesperline` for the `pix` union member.
fn pix_bytesperline(&self) -> u32 {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
pix.bytesperline
}
/// Get the field `sizeimage` for the `pix` union member.
fn pix_sizeimage(&self) -> u32 {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
pix.sizeimage
}
/// Get the field `colorspace` for the `pix` union member.
fn pix_colorspace(&self) -> Result<enums::Colorspace> {
let fmt = self.as_ref();
let pix = &unsafe { fmt.fmt.pix };
enums::Colorspace::try_from(pix.colorspace)
}
/// Set the field `field` for the `pix` union member.
fn set_pix_field(&mut self, field: enums::Field) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.field = field as u32;
}
/// Set the field `width` for the `pix` union member.
fn set_pix_width(&mut self, width: u32) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.width = width;
}
/// Set the field `height` for the `pix` union member.
fn set_pix_height(&mut self, height: u32) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.height = height;
}
/// Set the field `pixelformat` for the `pix` union member.
fn set_pix_pixel_format(&mut self, pixel_format: u32) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.pixelformat = pixel_format;
}
/// Set the field `bytesperline` for the `pix` union member.
fn set_pix_bytesperline(&mut self, bytesperline: u32) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.bytesperline = bytesperline;
}
/// Set the field `sizeimage` for the `pix` union member.
fn set_pix_sizeimage(&mut self, sizeimage: u32) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.sizeimage = sizeimage;
}
/// Set the field `sizeimage` for the `pix` union member.
fn set_pix_colorspace(&mut self, colorspace: enums::Colorspace) {
let fmt = self.as_mut();
let pix = &mut unsafe { fmt.fmt.pix };
pix.colorspace = colorspace as u32;
}
}
/// A wrapper over a pointer to `struct v4l2_format`.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct FormatRef(*mut bindings::v4l2_format);
impl FormatRef {
/// # Safety
/// The caller must ensure that `ptr` is valid and remains valid
for the lifetime of the
/// returned [`FormatRef`] instance.
pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_format) -> Self {
Self(ptr)
}
}
impl AsRef<bindings::v4l2_format> for FormatRef {
fn as_ref(&self) -> &bindings::v4l2_format {
// SAFETY: ptr is safe during the lifetime of [`FormatRef`] as
per
// the safety requirement in `from_ptr()`
unsafe { self.0.as_ref().unwrap() }
}
}
impl AsMut<bindings::v4l2_format> for FormatRef {
fn as_mut(&mut self) -> &mut bindings::v4l2_format {
// SAFETY: ptr is safe during the lifetime of [`FormatRef`] as
per
// the safety requirement in `from_ptr()`
unsafe { self.0.as_mut().unwrap() }
}
}
impl FormatImpl for FormatRef {}
/// An owned version of `FormatRef`.
#[derive(Default)]
pub struct Format(UnsafeCell<bindings::v4l2_format>);
impl AsRef<bindings::v4l2_format> for Format {
fn as_ref(&self) -> &bindings::v4l2_format {
// SAFETY:
// It is safe to dereference the pointer since it is valid
whenever this type is instantiated.
// It is safe to cast this into a shared reference: because
this is the
// only method that returns &bindings::v4l2_format and because
we take
// &self, the compiler takes care of enforcing the Rust
reference rules for
// us. Thus, enforcing the safety guarantees of
UnsafeCell::get() by
// proxy.
unsafe { &*self.0.get() }
}
}
impl AsMut<bindings::v4l2_format> for Format {
fn as_mut(&mut self) -> &mut bindings::v4l2_format {
// SAFETY:
// It is safe to dereference the pointer since it is valid
whenever this type is instantiated.
// It is safe to cast this into an exclusive reference: because
this is the
// only method that returns &mut bindings::v4l2_format and
because we take
// &mut self, the compiler takes care of enforcing the Rust
reference rules for
// us. Thus, enforcing the safety guarantees of
UnsafeCell::get() by
// proxy.
unsafe { &mut *self.0.get() }
}
}
impl FormatImpl for Format {}
```
This makes it possible to:
- Share the implementations between Format and FormatRef,
- Have both Format (while paying the cost of storing the
bindings::v4l2_format member) and FormatRef (while paying the cost of
storing a pointer) separately.
- Be generic over Format and FormatRef when needed, e.g.:
```
fn some_fn(format: impl FormatImpl) {...}
```
Thoughts?
-- Daniel
next prev parent reply other threads:[~2023-04-08 19:06 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-06 21:56 [PATCH 0/6] Initial Rust V4L2 support Daniel Almeida
2023-04-06 21:56 ` [PATCH 1/6] rust: media: add the media module Daniel Almeida
2023-04-06 21:56 ` [PATCH 2/6] rust: media: add initial videodev2.h abstractions Daniel Almeida
2023-04-06 21:56 ` [PATCH 3/6] rust: sync: introduce FfiMutex Daniel Almeida
2023-04-06 21:56 ` [PATCH 4/6] rust: media: videobuf2: add a videobuf2 abstraction Daniel Almeida
2023-04-06 21:56 ` [PATCH 5/6] rust: media: add {video|v4l2}_device_register support Daniel Almeida
2023-04-06 21:56 ` [PATCH 6/6] rust: media: add v4l2 rust sample Daniel Almeida
2023-04-08 19:06 ` Daniel Almeida [this message]
2023-04-08 19:43 ` [PATCH 0/6] Initial Rust V4L2 support Hans Petter Selasky
2023-04-09 14:10 ` Daniel Almeida
2023-04-10 18:59 ` Hans Petter Selasky
2023-04-10 23:41 ` Miguel Ojeda
2023-04-11 9:52 ` Hans Petter Selasky
2023-04-11 12:36 ` Miguel Ojeda
2023-04-11 13:15 ` Hans Petter Selasky
2023-04-11 14:19 ` Miguel Ojeda
2023-04-11 15:33 ` Hans Petter Selasky
2023-04-11 19:22 ` Miguel Ojeda
2023-04-12 10:00 ` Hans Petter Selasky
2023-04-12 10:13 ` Greg KH
2023-04-12 10:23 ` Hans Petter Selasky
2023-04-10 23:40 ` Miguel Ojeda
2023-04-26 14:31 ` Enrico Weigelt, metux IT consult
2023-04-10 22:46 ` Deborah Brouwer
2023-04-11 14:22 ` Miguel Ojeda
2023-04-12 2:58 ` Theodore Ts'o
2023-04-12 12:21 ` Miguel Ojeda
2023-04-12 12:38 ` Morten Linderud
2023-04-12 18:44 ` Nicolas Dufresne
[not found] ` <aae753d6-6874-4f91-e7ba-bd6c77f07b62@metux.net>
2023-04-26 15:33 ` Miguel Ojeda
2023-04-11 7:51 ` Hans Verkuil
2023-04-11 12:02 ` Miguel Ojeda
2023-04-11 12:49 ` Willy Tarreau
2023-04-11 14:01 ` Daniel Almeida
2023-04-11 14:13 ` Miguel Ojeda
2023-04-11 16:52 ` Willy Tarreau
2023-04-11 19:27 ` Miguel Ojeda
2023-04-11 20:26 ` Willy Tarreau
2023-04-11 22:14 ` Miguel Ojeda
[not found] ` <0da49a77-14d8-cb9d-e36d-985699746b6b@metux.net>
2023-04-26 16:05 ` Miguel Ojeda
2023-04-26 0:32 ` Laurent Pinchart
[not found] ` <57ec90ad-8535-fa7d-d6de-d5c1d06f37d3@metux.net>
2023-04-26 13:29 ` Laurent Pinchart
2023-04-26 16:18 ` Miguel Ojeda
2023-04-26 16:35 ` Laurent Pinchart
2023-04-26 17:14 ` Daniel Almeida
2023-04-26 17:25 ` Laurent Pinchart
2023-05-01 20:10 ` Nicolas Dufresne
2023-05-01 20:17 ` Asahi Lina
2023-05-01 20:19 ` Nicolas Dufresne
2023-05-02 19:13 ` Miguel Ojeda
2023-05-03 11:00 ` Daniel Almeida
2023-04-26 19:58 ` Sakari Ailus
2023-07-05 6:40 ` Hans Verkuil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0062de67bfe89653ffdc5e3c564fb24bc1adf3f4.camel@collabora.com \
--to=daniel.almeida@collabora.com \
--cc=hverkuil@xs4all.nl \
--cc=kernel@collabora.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).