Message ID | 20230119174036.64046-2-wedsonaf@gmail.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp460160wrn; Thu, 19 Jan 2023 09:45:48 -0800 (PST) X-Google-Smtp-Source: AMrXdXvQr1BdDjz/+5CV3S56B1eT3ruAs9+PjV094GFg+s3f+KLtgQzQ2ZtgfHrDw/XOtzTbxKyh X-Received: by 2002:a17:90a:4fa4:b0:226:f7d7:50f4 with SMTP id q33-20020a17090a4fa400b00226f7d750f4mr34780322pjh.21.1674150347798; Thu, 19 Jan 2023 09:45:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674150347; cv=none; d=google.com; s=arc-20160816; b=cfVFGuGkE77SX+fzeJhf0oDkAQQ9ZU3CEjTa74olX03VNdVZ2CxyElBuUxwPQsc/1+ 6J1Sws3hUh/5GDCguFjHJ+TdWc+YTUAkvAW7JbkKL+mA49z7gAlSvww+vQF7wlcsmZjz j46Fdy2Di5VWcLE068A3se8eDqBSIQHslmvczW8q2Kx1+oDch7llO6FHaDQiPHQBpiBp 6Akd79QCM96EyaaoMv25yeNfojCuUGCIA5aubiohnODuicUxANf1LHr0EB2IJZ3PKjmK EhCmyH2lFItnEyNcOruCzeCsXh8eQ6s3HbLjt7VoCnGHY8spgVpYWU5GA4PEyEASqpOH 7fDQ== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ZwxU4+6BfOCgB1/4NzWZU6FV5+g31u+lXUwKNUQPWUE=; b=WvwwU5rWT0L5JpHeQMkYWtutluYYnO/a5zQmrgA7Pl1/3CdL5E92wueGB0xkOQjHXo JRimlOwXOD5qWWnhrteHWrGVWeJQHyqTo0NICeDRkSiWxzvv3Qpqh//EM6TZfL+C2WPQ 3sBBBmXV48trnJom+6BszQJm9BpK3wAEC2tF1sI5jUY/+YXNCDZlj/d+hrh9DpqghCZ5 zuiBawneIxRnkaT6jdXod1R8wJJ5XMPljOqhfgWjyKNgfJg44nR8+cc0ZsbyaN481J9o Tmskm7D2hCIkNcyCDfoR2kBldaxQkEC/vhLiWa8XD1P33pxI0l7D4bTH1dEeKK8ZXwzE 42DA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=c+dYUuSK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id np5-20020a17090b4c4500b002238dff236esi7007311pjb.148.2023.01.19.09.45.35; Thu, 19 Jan 2023 09:45:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=c+dYUuSK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230077AbjASRl1 (ORCPT <rfc822;pfffrao@gmail.com> + 99 others); Thu, 19 Jan 2023 12:41:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229852AbjASRlV (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 19 Jan 2023 12:41:21 -0500 Received: from mail-oa1-x33.google.com (mail-oa1-x33.google.com [IPv6:2001:4860:4864:20::33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A676490857; Thu, 19 Jan 2023 09:41:02 -0800 (PST) Received: by mail-oa1-x33.google.com with SMTP id 586e51a60fabf-12c8312131fso3396868fac.4; Thu, 19 Jan 2023 09:41:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZwxU4+6BfOCgB1/4NzWZU6FV5+g31u+lXUwKNUQPWUE=; b=c+dYUuSKYuS+4cZUhnvuhXuGCB2QiKzx0DR+8tgWN3eHX5UzXiXHfHfTwj2WoMmzYH ba5Qtrz3izgo0A2Q13X3Vu3pZ/YhqWE+kCyY53E+Lq/wAGaPoaZRyGMJ04He/K+7g9yK eahq4wyCfE0+HlAZJG1aRwK/g+M2QdGhKcPC5lj94CdgILTaStho2MHfxhq9hj67R2Fb 9FV3sJD1kmT/JnOpLuNmUR3Qd3d363foX4A7w9mJTBBLraIxdMFjuYYpuSoiM9R/eixg f19OufXWkBCWzaxc1RLq6HoiJug6w44q3buT5J689WzbLCe4PGRN8gBHKSkxvMbZFqc3 vxpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZwxU4+6BfOCgB1/4NzWZU6FV5+g31u+lXUwKNUQPWUE=; b=q09sSd150cPkyqeKc1L1rJ0reo4T5F0T9xPk2PiOWgpBHVH8kloLLVHTMsOarfhw8v QcT9g5gn7wz0JlmvClvMEiu8kkXSMrdixvV2fkledHvzEutPKiNENAyE6qXtIHkDV6e0 KzcWEhctkaeXavsAboKIjE4QeOxxu2mn/4BCn0rLmn0w62NXZOq3e8Sh1K3Ht3YVNt4w L9YqFp955l5rEuJfdae2M52RcEOOihqh0QSeqP9o5rWwnmmESMn5P0GArvZ58dj6oz2C OIP97D3koj8TW2oFMiI2V15oC3c7HVD/4KqNld5UO8uq/N1z+fg1A+qT/gtWlZ9EPRAW hnIw== X-Gm-Message-State: AFqh2kqs8qJ74GJTL5xXkSGi9dPzQmizFchgORWPzqDrg618P0Z5LcIQ rTZeWOgv+9Xplk/ZOk355qRfPwZVlq9JGpbe X-Received: by 2002:a05:6870:659e:b0:15e:d586:6d46 with SMTP id fp30-20020a056870659e00b0015ed5866d46mr15435524oab.34.1674150061906; Thu, 19 Jan 2023 09:41:01 -0800 (PST) Received: from wedsonaf-dev.home.lan ([189.124.190.154]) by smtp.googlemail.com with ESMTPSA id i7-20020a056808054700b003631fe1810dsm10226906oig.47.2023.01.19.09.40.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Jan 2023 09:41:01 -0800 (PST) From: Wedson Almeida Filho <wedsonaf@gmail.com> To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda <ojeda@kernel.org>, Alex Gaynor <alex.gaynor@gmail.com>, Boqun Feng <boqun.feng@gmail.com>, Gary Guo <gary@garyguo.net>, =?utf-8?q?B?= =?utf-8?q?j=C3=B6rn_Roy_Baron?= <bjorn3_gh@protonmail.com>, linux-kernel@vger.kernel.org, Wedson Almeida Filho <wedsonaf@gmail.com> Subject: [PATCH 2/5] rust: types: introduce `ForeignOwnable` Date: Thu, 19 Jan 2023 14:40:33 -0300 Message-Id: <20230119174036.64046-2-wedsonaf@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230119174036.64046-1-wedsonaf@gmail.com> References: <20230119174036.64046-1-wedsonaf@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755473875293850318?= X-GMAIL-MSGID: =?utf-8?q?1755473875293850318?= |
Series | [1/5] rust: types: introduce `ScopeGuard` | |
Commit Message
Wedson Almeida Filho
Jan. 19, 2023, 5:40 p.m. UTC
It was originally called `PointerWrapper`. It is used to convert
a Rust object to a pointer representation (void *) that can be
stored on the C side, used, and eventually returned to Rust.
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
---
rust/kernel/lib.rs | 1 +
rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
Comments
On Thu, Jan 19, 2023 at 02:40:33PM -0300, Wedson Almeida Filho wrote: > It was originally called `PointerWrapper`. It is used to convert > a Rust object to a pointer representation (void *) that can be > stored on the C side, used, and eventually returned to Rust. > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index e0b0e953907d..223564f9f0cc 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -16,6 +16,7 @@ > #![feature(coerce_unsized)] > #![feature(core_ffi_c)] > #![feature(dispatch_from_dyn)] > +#![feature(generic_associated_types)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > index f0ad4472292d..5475f6163002 100644 > --- a/rust/kernel/types.rs > +++ b/rust/kernel/types.rs > @@ -9,6 +9,60 @@ use core::{ > ops::{Deref, DerefMut}, > }; > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > +/// > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > +/// > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > +/// eventually "freed" back to Rust. > +pub trait ForeignOwnable { > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > + /// [`ForeignOwnable::from_foreign`]. > + type Borrowed<'a>; > + > + /// Converts a Rust-owned object to a foreign-owned one. > + /// > + /// The foreign representation is a pointer to void. > + fn into_foreign(self) -> *const core::ffi::c_void; > + > + /// Borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > + /// for this object must have been dropped. > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > + > + /// Mutably borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > + // `into_foreign`. > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > + d.into_foreign(); > + }) I kinda want to suggest borrow_mut() to be implemented as: pub trait ForeignOwnable { ... unsafe fn borrow_mut(ptr: *const core::ffi::c_void) -> ScopeGuard<Self, fn(Self)> { // SAFETY: The safety requirements ensure that `ptr` came from a previous call to // `into_foreign`. ScopeGuard::new_with_data(unsafe { Self::from_foreign(ptr) }, |d| { d.into_foreign(); }) } to avoid funny code as follow: let a = Box::new(0).into_foreign(); // Using an irrelevant `impl ForeignOwnable` to `borrow_mut` let borrowed_a: ScopeGuard<Box<i32>, ...> = unsafe { Arc::<u64>::borrow_mut(a) }; but that requires `Self: Sized`. Is it too restrictive? Regards, Boqun > + } > + > + /// Converts a foreign-owned object back to a Rust-owned one. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > +} > + > /// Runs a cleanup function/closure when dropped. > /// > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > -- > 2.34.1 >
On Fri, 20 Jan 2023 at 16:59, Boqun Feng <boqun.feng@gmail.com> wrote: > > On Thu, Jan 19, 2023 at 02:40:33PM -0300, Wedson Almeida Filho wrote: > > It was originally called `PointerWrapper`. It is used to convert > > a Rust object to a pointer representation (void *) that can be > > stored on the C side, used, and eventually returned to Rust. > > > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> > > --- > > rust/kernel/lib.rs | 1 + > > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 55 insertions(+) > > > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > > index e0b0e953907d..223564f9f0cc 100644 > > --- a/rust/kernel/lib.rs > > +++ b/rust/kernel/lib.rs > > @@ -16,6 +16,7 @@ > > #![feature(coerce_unsized)] > > #![feature(core_ffi_c)] > > #![feature(dispatch_from_dyn)] > > +#![feature(generic_associated_types)] > > #![feature(receiver_trait)] > > #![feature(unsize)] > > > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > > index f0ad4472292d..5475f6163002 100644 > > --- a/rust/kernel/types.rs > > +++ b/rust/kernel/types.rs > > @@ -9,6 +9,60 @@ use core::{ > > ops::{Deref, DerefMut}, > > }; > > > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > > +/// > > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > > +/// > > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > > +/// eventually "freed" back to Rust. > > +pub trait ForeignOwnable { > > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > > + /// [`ForeignOwnable::from_foreign`]. > > + type Borrowed<'a>; > > + > > + /// Converts a Rust-owned object to a foreign-owned one. > > + /// > > + /// The foreign representation is a pointer to void. > > + fn into_foreign(self) -> *const core::ffi::c_void; > > + > > + /// Borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > > + /// for this object must have been dropped. > > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > > + > > + /// Mutably borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > > + // `into_foreign`. > > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > > + d.into_foreign(); > > + }) > > I kinda want to suggest borrow_mut() to be implemented as: > > pub trait ForeignOwnable { > ... > unsafe fn borrow_mut(ptr: *const core::ffi::c_void) -> ScopeGuard<Self, fn(Self)> { > // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > // `into_foreign`. > ScopeGuard::new_with_data(unsafe { Self::from_foreign(ptr) }, |d| { > d.into_foreign(); > }) > } Oh, eliminate the generic type `T` and just use `Self`. Yes, I think that's a good simplification. > > to avoid funny code as follow: > > let a = Box::new(0).into_foreign(); > // Using an irrelevant `impl ForeignOwnable` to `borrow_mut` > let borrowed_a: ScopeGuard<Box<i32>, ...> = unsafe { Arc::<u64>::borrow_mut(a) }; > > but that requires `Self: Sized`. Is it too restrictive? It isn't. Since we want the raw pointer to fit in a single pointer (from C's perspective), we already require `Self: Sized`. I'll make this change in v2. > > Regards, > Boqun > > > + } > > + > > + /// Converts a foreign-owned object back to a Rust-owned one. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > > +} > > + > > /// Runs a cleanup function/closure when dropped. > > /// > > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > > -- > > 2.34.1 > >
On Thu, 19 Jan 2023 14:40:33 -0300 Wedson Almeida Filho <wedsonaf@gmail.com> wrote: > It was originally called `PointerWrapper`. It is used to convert > a Rust object to a pointer representation (void *) that can be > stored on the C side, used, and eventually returned to Rust. > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index e0b0e953907d..223564f9f0cc 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -16,6 +16,7 @@ > #![feature(coerce_unsized)] > #![feature(core_ffi_c)] > #![feature(dispatch_from_dyn)] > +#![feature(generic_associated_types)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > index f0ad4472292d..5475f6163002 100644 > --- a/rust/kernel/types.rs > +++ b/rust/kernel/types.rs > @@ -9,6 +9,60 @@ use core::{ > ops::{Deref, DerefMut}, > }; > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > +/// > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > +/// > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > +/// eventually "freed" back to Rust. > +pub trait ForeignOwnable { > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > + /// [`ForeignOwnable::from_foreign`]. > + type Borrowed<'a>; > + > + /// Converts a Rust-owned object to a foreign-owned one. > + /// > + /// The foreign representation is a pointer to void. > + fn into_foreign(self) -> *const core::ffi::c_void; > + > + /// Borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > + /// for this object must have been dropped. > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > + > + /// Mutably borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { I feel that this should could its own guard (maybe `PointerGuard`?) to be more semantically meaningful than a `ScopeGuard`. > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > + // `into_foreign`. > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > + d.into_foreign(); > + }) > + } > + > + /// Converts a foreign-owned object back to a Rust-owned one. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > +} > + > /// Runs a cleanup function/closure when dropped. > /// > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
On Thu Jan 19, 2023 at 6:40 PM CET, Wedson Almeida Filho wrote: > It was originally called `PointerWrapper`. It is used to convert > a Rust object to a pointer representation (void *) that can be > stored on the C side, used, and eventually returned to Rust. > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> Reviewed-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index e0b0e953907d..223564f9f0cc 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -16,6 +16,7 @@ > #![feature(coerce_unsized)] > #![feature(core_ffi_c)] > #![feature(dispatch_from_dyn)] > +#![feature(generic_associated_types)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > index f0ad4472292d..5475f6163002 100644 > --- a/rust/kernel/types.rs > +++ b/rust/kernel/types.rs > @@ -9,6 +9,60 @@ use core::{ > ops::{Deref, DerefMut}, > }; > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > +/// > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > +/// > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > +/// eventually "freed" back to Rust. > +pub trait ForeignOwnable { > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > + /// [`ForeignOwnable::from_foreign`]. > + type Borrowed<'a>; > + > + /// Converts a Rust-owned object to a foreign-owned one. > + /// > + /// The foreign representation is a pointer to void. > + fn into_foreign(self) -> *const core::ffi::c_void; > + > + /// Borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > + /// for this object must have been dropped. > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > + > + /// Mutably borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > + // `into_foreign`. > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > + d.into_foreign(); > + }) > + } > + > + /// Converts a foreign-owned object back to a Rust-owned one. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > +} > + > /// Runs a cleanup function/closure when dropped. > /// > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > -- > 2.34.1
On Thu, Jan 19, 2023 at 02:40:33PM -0300, Wedson Almeida Filho wrote: > It was originally called `PointerWrapper`. It is used to convert > a Rust object to a pointer representation (void *) that can be > stored on the C side, used, and eventually returned to Rust. > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index e0b0e953907d..223564f9f0cc 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -16,6 +16,7 @@ > #![feature(coerce_unsized)] > #![feature(core_ffi_c)] > #![feature(dispatch_from_dyn)] > +#![feature(generic_associated_types)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > index f0ad4472292d..5475f6163002 100644 > --- a/rust/kernel/types.rs > +++ b/rust/kernel/types.rs > @@ -9,6 +9,60 @@ use core::{ > ops::{Deref, DerefMut}, > }; > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > +/// > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > +/// > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > +/// eventually "freed" back to Rust. > +pub trait ForeignOwnable { > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > + /// [`ForeignOwnable::from_foreign`]. > + type Borrowed<'a>; Is it there a possibility that this could make use of borrowing features like AsRef/Borrowed/Deref? > + > + /// Converts a Rust-owned object to a foreign-owned one. > + /// > + /// The foreign representation is a pointer to void. > + fn into_foreign(self) -> *const core::ffi::c_void; > + > + /// Borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > + /// for this object must have been dropped. > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > + > + /// Mutably borrows a foreign-owned object. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > + // `into_foreign`. > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > + d.into_foreign(); > + }) > + } Could these three methods have a borrowing equivalent? When I was working on some features for the USB module I've stumbled upon the case of having to encode a pointer (with a pivot) and I cannot do it without taking ownership of the pointer. > + > + /// Converts a foreign-owned object back to a Rust-owned one. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > +} > + > /// Runs a cleanup function/closure when dropped. > /// > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > -- > 2.34.1 Aside from these comments I observe that there's a possibility to make ForeignOwnable a const trait and have non const implementors. Otherwise if these things are out of scope, no problem whatsoever and this has my OK. Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On Sat, Jan 28, 2023 at 11:53:45AM -0300, Martin Rodriguez Reboredo wrote: [...] > > + /// Borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > > + /// for this object must have been dropped. > > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > > + > > + /// Mutably borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > > + // `into_foreign`. > > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > > + d.into_foreign(); > > + }) > > + } > > Could these three methods have a borrowing equivalent? When I was > working on some features for the USB module I've stumbled upon the case > of having to encode a pointer (with a pivot) and I cannot do it without > taking ownership of the pointer. > *const T is Copy, so you can still use it after pass it to a function or a new binding, e.g. pub fn use_ptr(ptr: *const i32) { .. } let p: *const i32 = some_func(); let q = p; // q is just a copy of p use_ptr(p); // passing to a function parameter is just copying use_ptr(p); maybe I'm missing something subtle, but if you have an example I can help take a look. Regards, Boqun > > + > > + /// Converts a foreign-owned object back to a Rust-owned one. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > > +} > > + > > /// Runs a cleanup function/closure when dropped. > > /// > > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > > -- > > 2.34.1 > > Aside from these comments I observe that there's a possibility to make > ForeignOwnable a const trait and have non const implementors. Otherwise > if these things are out of scope, no problem whatsoever and this has my > OK. > > Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On 1/28/23 14:05, Boqun Feng wrote: > On Sat, Jan 28, 2023 at 11:53:45AM -0300, Martin Rodriguez Reboredo wrote: > [...] >>> + /// Borrows a foreign-owned object. >>> + /// >>> + /// # Safety >>> + /// >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] >>> + /// for this object must have been dropped. >>> + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; >>> + >>> + /// Mutably borrows a foreign-owned object. >>> + /// >>> + /// # Safety >>> + /// >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and >>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. >>> + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { >>> + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to >>> + // `into_foreign`. >>> + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { >>> + d.into_foreign(); >>> + }) >>> + } >> >> Could these three methods have a borrowing equivalent? When I was >> working on some features for the USB module I've stumbled upon the case >> of having to encode a pointer (with a pivot) and I cannot do it without >> taking ownership of the pointer. >> > > *const T is Copy, so you can still use it after pass it to a function or > a new binding, e.g. > > pub fn use_ptr(ptr: *const i32) { .. } > > let p: *const i32 = some_func(); > > let q = p; > > // q is just a copy of p > use_ptr(p); > // passing to a function parameter is just copying > use_ptr(p); > > maybe I'm missing something subtle, but if you have an example I can > help take a look. > > Regards, > Boqun > I'll use a much more simple example. If I want to take the byte offset between two `ForeignWrapper`s I'd have to take ownership of them, but I don't see it desirable in some cases. fn byte_offset<P: PointerWrapper>(ptr: P, pivot: P) -> isize { unsafe { ptr.into_pointer().cast::<u8>() .byte_offset(pivot.into_pointer().cast()) } } But if there was an `as_pointer(&self) -> *const c_void` method then the above function will be able to borrow both `ForeignWrapper`s. fn byte_offset<P: PointerWrapper>(ptr: &P, pivot: &P) -> isize { unsafe { ptr.as_pointer().cast::<u8>() .byte_offset(pivot.as_pointer().cast()) } } Obviously those methods that borrow will announce invariancies in their doc comments. If these can exist then great and if not then another solution could be explored. >>> + >>> + /// Converts a foreign-owned object back to a Rust-owned one. >>> + /// >>> + /// # Safety >>> + /// >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and >>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. >>> + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; >>> +} >>> + >>> /// Runs a cleanup function/closure when dropped. >>> /// >>> /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. >>> -- >>> 2.34.1 >> >> Aside from these comments I observe that there's a possibility to make >> ForeignOwnable a const trait and have non const implementors. Otherwise >> if these things are out of scope, no problem whatsoever and this has my >> OK. >> >> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On Sat, Jan 28, 2023 at 05:46:50PM -0300, Martin Rodriguez Reboredo wrote: > On 1/28/23 14:05, Boqun Feng wrote: > > On Sat, Jan 28, 2023 at 11:53:45AM -0300, Martin Rodriguez Reboredo wrote: > > [...] > >>> + /// Borrows a foreign-owned object. > >>> + /// > >>> + /// # Safety > >>> + /// > >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > >>> + /// for this object must have been dropped. > >>> + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > >>> + > >>> + /// Mutably borrows a foreign-owned object. > >>> + /// > >>> + /// # Safety > >>> + /// > >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > >>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > >>> + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > >>> + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > >>> + // `into_foreign`. > >>> + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > >>> + d.into_foreign(); > >>> + }) > >>> + } > >> > >> Could these three methods have a borrowing equivalent? When I was > >> working on some features for the USB module I've stumbled upon the case > >> of having to encode a pointer (with a pivot) and I cannot do it without > >> taking ownership of the pointer. > >> > > > > *const T is Copy, so you can still use it after pass it to a function or > > a new binding, e.g. > > > > pub fn use_ptr(ptr: *const i32) { .. } > > > > let p: *const i32 = some_func(); > > > > let q = p; > > > > // q is just a copy of p > > use_ptr(p); > > // passing to a function parameter is just copying > > use_ptr(p); > > > > maybe I'm missing something subtle, but if you have an example I can > > help take a look. > > > > Regards, > > Boqun > > > > I'll use a much more simple example. If I want to take the byte offset > between two `ForeignWrapper`s I'd have to take ownership of them, but I > don't see it desirable in some cases. > > fn byte_offset<P: PointerWrapper>(ptr: P, pivot: P) -> isize { > unsafe { > ptr.into_pointer().cast::<u8>() > .byte_offset(pivot.into_pointer().cast()) > } > } > > But if there was an `as_pointer(&self) -> *const c_void` method then the > above function will be able to borrow both `ForeignWrapper`s. > > fn byte_offset<P: PointerWrapper>(ptr: &P, pivot: &P) -> isize { > unsafe { > ptr.as_pointer().cast::<u8>() > .byte_offset(pivot.as_pointer().cast()) > } > } > > Obviously those methods that borrow will announce invariancies in their > doc comments. If these can exist then great and if not then another > solution could be explored. > For this particular use case, IIUC, what you need is exactly `AsRef`: fn byte_offset<T, P: AsRef<T>>(ptr: &P, pivot: &P) -> isize { unsafe { (ptr.as_ref() as *const _).cast::<u8>() .byte_offset((pivot.as_ref() *const _).cast()) } } or you can implement a as_pointer() helper function to avoid the duplicate `.as_ref() as *const _`: fn as_pointer<T, P: AsRef<T>>(ptr: &P) -> *const T { ptr.as_ref() as *const T } Although, we need to `impl AsRef<T> for Arc<T>` to make it work for `Arc<T>`, which is currently missing. Regards, Boqun > >>> + > >>> + /// Converts a foreign-owned object back to a Rust-owned one. > >>> + /// > >>> + /// # Safety > >>> + /// > >>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > >>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > >>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > >>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > >>> + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > >>> +} > >>> + > >>> /// Runs a cleanup function/closure when dropped. > >>> /// > >>> /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > >>> -- > >>> 2.34.1 > >> > >> Aside from these comments I observe that there's a possibility to make > >> ForeignOwnable a const trait and have non const implementors. Otherwise > >> if these things are out of scope, no problem whatsoever and this has my > >> OK. > >> > >> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On 1/28/23 19:07, Boqun Feng wrote: > On Sat, Jan 28, 2023 at 05:46:50PM -0300, Martin Rodriguez Reboredo wrote: >> On 1/28/23 14:05, Boqun Feng wrote: >>> On Sat, Jan 28, 2023 at 11:53:45AM -0300, Martin Rodriguez Reboredo wrote: >>> [...] >>>>> + /// Borrows a foreign-owned object. >>>>> + /// >>>>> + /// # Safety >>>>> + /// >>>>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>>>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>>>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] >>>>> + /// for this object must have been dropped. >>>>> + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; >>>>> + >>>>> + /// Mutably borrows a foreign-owned object. >>>>> + /// >>>>> + /// # Safety >>>>> + /// >>>>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>>>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>>>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and >>>>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. >>>>> + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { >>>>> + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to >>>>> + // `into_foreign`. >>>>> + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { >>>>> + d.into_foreign(); >>>>> + }) >>>>> + } >>>> >>>> Could these three methods have a borrowing equivalent? When I was >>>> working on some features for the USB module I've stumbled upon the case >>>> of having to encode a pointer (with a pivot) and I cannot do it without >>>> taking ownership of the pointer. >>>> >>> >>> *const T is Copy, so you can still use it after pass it to a function or >>> a new binding, e.g. >>> >>> pub fn use_ptr(ptr: *const i32) { .. } >>> >>> let p: *const i32 = some_func(); >>> >>> let q = p; >>> >>> // q is just a copy of p >>> use_ptr(p); >>> // passing to a function parameter is just copying >>> use_ptr(p); >>> >>> maybe I'm missing something subtle, but if you have an example I can >>> help take a look. >>> >>> Regards, >>> Boqun >>> >> >> I'll use a much more simple example. If I want to take the byte offset >> between two `ForeignWrapper`s I'd have to take ownership of them, but I >> don't see it desirable in some cases. >> >> fn byte_offset<P: PointerWrapper>(ptr: P, pivot: P) -> isize { >> unsafe { >> ptr.into_pointer().cast::<u8>() >> .byte_offset(pivot.into_pointer().cast()) >> } >> } >> >> But if there was an `as_pointer(&self) -> *const c_void` method then the >> above function will be able to borrow both `ForeignWrapper`s. >> >> fn byte_offset<P: PointerWrapper>(ptr: &P, pivot: &P) -> isize { >> unsafe { >> ptr.as_pointer().cast::<u8>() >> .byte_offset(pivot.as_pointer().cast()) >> } >> } >> >> Obviously those methods that borrow will announce invariancies in their >> doc comments. If these can exist then great and if not then another >> solution could be explored. >> > > For this particular use case, IIUC, what you need is exactly `AsRef`: > > fn byte_offset<T, P: AsRef<T>>(ptr: &P, pivot: &P) -> isize { > unsafe { > (ptr.as_ref() as *const _).cast::<u8>() > .byte_offset((pivot.as_ref() *const _).cast()) > } > } > > or you can implement a as_pointer() helper function to avoid the > duplicate `.as_ref() as *const _`: > > fn as_pointer<T, P: AsRef<T>>(ptr: &P) -> *const T { > ptr.as_ref() as *const T > } > > Although, we need to `impl AsRef<T> for Arc<T>` to make it work for > `Arc<T>`, which is currently missing. > > Regards, > Boqun > Now that you say it I think that I can do what I wanted by further constraining it to `ForeignOwnable` plus `AsRef`, so thanks for the tip Boqun. >>>>> + >>>>> + /// Converts a foreign-owned object back to a Rust-owned one. >>>>> + /// >>>>> + /// # Safety >>>>> + /// >>>>> + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for >>>>> + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. >>>>> + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and >>>>> + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. >>>>> + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; >>>>> +} >>>>> + >>>>> /// Runs a cleanup function/closure when dropped. >>>>> /// >>>>> /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. >>>>> -- >>>>> 2.34.1 >>>> >>>> Aside from these comments I observe that there's a possibility to make >>>> ForeignOwnable a const trait and have non const implementors. Otherwise >>>> if these things are out of scope, no problem whatsoever and this has my >>>> OK. >>>> >>>> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On Fri, 27 Jan 2023 at 10:55, Gary Guo <gary@garyguo.net> wrote: > > On Thu, 19 Jan 2023 14:40:33 -0300 > Wedson Almeida Filho <wedsonaf@gmail.com> wrote: > > > It was originally called `PointerWrapper`. It is used to convert > > a Rust object to a pointer representation (void *) that can be > > stored on the C side, used, and eventually returned to Rust. > > > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> > > --- > > rust/kernel/lib.rs | 1 + > > rust/kernel/types.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 55 insertions(+) > > > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > > index e0b0e953907d..223564f9f0cc 100644 > > --- a/rust/kernel/lib.rs > > +++ b/rust/kernel/lib.rs > > @@ -16,6 +16,7 @@ > > #![feature(coerce_unsized)] > > #![feature(core_ffi_c)] > > #![feature(dispatch_from_dyn)] > > +#![feature(generic_associated_types)] > > #![feature(receiver_trait)] > > #![feature(unsize)] > > > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > > index f0ad4472292d..5475f6163002 100644 > > --- a/rust/kernel/types.rs > > +++ b/rust/kernel/types.rs > > @@ -9,6 +9,60 @@ use core::{ > > ops::{Deref, DerefMut}, > > }; > > > > +/// Used to transfer ownership to and from foreign (non-Rust) languages. > > +/// > > +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and > > +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. > > +/// > > +/// This trait is meant to be used in cases when Rust objects are stored in C objects and > > +/// eventually "freed" back to Rust. > > +pub trait ForeignOwnable { > > + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and > > + /// [`ForeignOwnable::from_foreign`]. > > + type Borrowed<'a>; > > + > > + /// Converts a Rust-owned object to a foreign-owned one. > > + /// > > + /// The foreign representation is a pointer to void. > > + fn into_foreign(self) -> *const core::ffi::c_void; > > + > > + /// Borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] > > + /// for this object must have been dropped. > > + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; > > + > > + /// Mutably borrows a foreign-owned object. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { > > I feel that this should could its own guard (maybe `PointerGuard`?) to > be more semantically meaningful than a `ScopeGuard`. I prefer not to add yet another type just for this internal type. It's only used in the implementation of abstractions, and is exported only to make it simpler for users to refer to types indirectly (e.g., `<T as ForeignOwnable>::Borrowed<'_>`). > > > + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to > > + // `into_foreign`. > > + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { > > + d.into_foreign(); > > + }) > > + } > > + > > + /// Converts a foreign-owned object back to a Rust-owned one. > > + /// > > + /// # Safety > > + /// > > + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for > > + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. > > + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and > > + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. > > + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; > > +} > > + > > /// Runs a cleanup function/closure when dropped. > > /// > > /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. >
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index e0b0e953907d..223564f9f0cc 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -16,6 +16,7 @@ #![feature(coerce_unsized)] #![feature(core_ffi_c)] #![feature(dispatch_from_dyn)] +#![feature(generic_associated_types)] #![feature(receiver_trait)] #![feature(unsize)] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index f0ad4472292d..5475f6163002 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -9,6 +9,60 @@ use core::{ ops::{Deref, DerefMut}, }; +/// Used to transfer ownership to and from foreign (non-Rust) languages. +/// +/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and +/// later may be transferred back to Rust by calling [`Self::from_foreign`]. +/// +/// This trait is meant to be used in cases when Rust objects are stored in C objects and +/// eventually "freed" back to Rust. +pub trait ForeignOwnable { + /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and + /// [`ForeignOwnable::from_foreign`]. + type Borrowed<'a>; + + /// Converts a Rust-owned object to a foreign-owned one. + /// + /// The foreign representation is a pointer to void. + fn into_foreign(self) -> *const core::ffi::c_void; + + /// Borrows a foreign-owned object. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] + /// for this object must have been dropped. + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; + + /// Mutably borrows a foreign-owned object. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. + unsafe fn borrow_mut<T: ForeignOwnable>(ptr: *const core::ffi::c_void) -> ScopeGuard<T, fn(T)> { + // SAFETY: The safety requirements ensure that `ptr` came from a previous call to + // `into_foreign`. + ScopeGuard::new_with_data(unsafe { T::from_foreign(ptr) }, |d| { + d.into_foreign(); + }) + } + + /// Converts a foreign-owned object back to a Rust-owned one. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and + /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; +} + /// Runs a cleanup function/closure when dropped. /// /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.