Received: by 2002:a05:6358:a55:b0:ec:fcf4:3ecf with SMTP id 21csp2200845rwb; Thu, 19 Jan 2023 22:58:31 -0800 (PST) X-Google-Smtp-Source: AMrXdXuRljRwWPP2GnhHXtTiqF0yW71zjkRszYfrDbWbudM4rwIkUEOPKIpouwUkMep+0HtaPZQ6 X-Received: by 2002:a05:6a20:b28f:b0:b8:e00a:c40c with SMTP id ei15-20020a056a20b28f00b000b8e00ac40cmr11315635pzb.62.1674197910650; Thu, 19 Jan 2023 22:58:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674197910; cv=none; d=google.com; s=arc-20160816; b=sh6FHXJJCSN6apF4enbPj3hG30VnaA+NHtSJ1pFIah9CRe0EVslUx1/MBcsGldIzzh p6fbFIZgV1y0YjNh3oIqG+LPCsX/XW3P/p75i7dHO02rzh5C6ETgm9O2J7wD4WLDFcii I8tJxCf+EuANDmxR9/ja3FF7XYff3SYS3YCydoRwDqXNdElOjam5seYx29P6uHR593Pg GVUrw7Tb6tWtZsF25XZ641YS0E6TmtOXncV5sOov78L4JVVxsm883Atd0Pgwk2j+5Mb2 Vj7DgbVm99nV2R8xaU4RnSmSc8KIpIDSBErJfHka9ayWp8evg67TBx8h17uNZouUTnmg rZXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date:feedback-id :dkim-signature; bh=m/MI+VcYhdwx96fyONVt/5n6r1oLpaMorbRp8iU9Y1A=; b=cSwAtPweP8wt7C+Ir53KcYjza1TU6u/aP4AL+2vqsIN7CLWBj/B6586QaO2MMgDRIv 4C4G+9qUueJJn4F6M0R1JVV/IPHVmd4YfiBECAVf+mAHnnzTg2evxSRgz3m3Uo7Meh9i o++ZG8lVCapRM3oTpLJdd+UXnGy2jfYoN8ZszpMvITkncf8V7ffQoOZnG3q6f2+bL1xi OpPGoJNfacqr6RU3cf2uiGhWxQnszhU/vjLhKioB5PBdy5uJv9K4gyCP2NJZwFZ0I2ZA lYMjLhnFb0Y+JDeiEKkHhlFhSp0z5yk2DHZsPiYy0Y0s4wkcKMIU1ijegwKLEZhjKS2f dPzg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=TctN8tdV; 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 Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id g19-20020a635653000000b004d274387e42si3315734pgm.578.2023.01.19.22.58.24; Thu, 19 Jan 2023 22:58:30 -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=TctN8tdV; 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 S229963AbjATGYj (ORCPT + 49 others); Fri, 20 Jan 2023 01:24:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229712AbjATGYd (ORCPT ); Fri, 20 Jan 2023 01:24:33 -0500 Received: from mail-qt1-x835.google.com (mail-qt1-x835.google.com [IPv6:2607:f8b0:4864:20::835]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB5A77CCCA; Thu, 19 Jan 2023 22:24:02 -0800 (PST) Received: by mail-qt1-x835.google.com with SMTP id x7so3438452qtv.13; Thu, 19 Jan 2023 22:24:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:feedback-id:from:to:cc:subject:date :message-id:reply-to; bh=m/MI+VcYhdwx96fyONVt/5n6r1oLpaMorbRp8iU9Y1A=; b=TctN8tdVzAAQVuXr7I+CkW7I1UpND2PNCiWNO+Uu98aJd0TyUEtqaOTghrptdHqQyz lfuJPlHOPG2uvNa31M5fVV2IhUQupLxNXESjDsk2sO/7MBSsQQKJfHhBuhmhiVvjW36U jwjd/Frt8o9nSBbeTpJsls834H4VqHOfnde0LaGIWcXsQAggQ+OYAjb4irf02Nwr6WLw A83cPqT5CSOq1ZtClGj036m+mwSNE5gPcgUoB/NYmeg0pEJV8FcFKrYGfZwSHBUPPJOf vHOoeXNYrhiIaW2j6g/v9/da2U5+fUPnya9op/u9CHvYk0YR5ZEBdJNJG63cope9ThgU pLzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:feedback-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=m/MI+VcYhdwx96fyONVt/5n6r1oLpaMorbRp8iU9Y1A=; b=g/PDHu6+I5MoOOg76QGjMQksSCS4uipL9YDGmbnzZUMWvxl9nOIBJL96aLyXFLusNK SzpaZmEMYcXMqFXfkgZ0WEXSN+uqk9jOiB3/Za7plpegYAEkhDYI1fO14PFyC6UZFIUp RtPPMzY4CrEZ5DcWwXLzBERL9UXYCFrwMSAPcePtB4kskMr69TCw0e2mNzk6G8wK2CBm mPWCatQmrdzQYsHKFsCPmtU76wwMNld6xK3e4PENEOswgjbq7FCKnx8hUvC1G8C4EdaT DqXk6EyiTpvmhR3GdIIGnDH5tK6CcQWZEYJUXUBX0x971Ih6YCthrL7e5o22m6v7bv7H uXKw== X-Gm-Message-State: AFqh2koSPpA1HttiWXiYRhCGunqwxmdCE4qi/IeYheDpT7aQ2a3vkF5h LvTjPhSiV2lzY3oR0J14i6e0qpsbP28= X-Received: by 2002:ac8:7a93:0:b0:3b1:c538:7026 with SMTP id x19-20020ac87a93000000b003b1c5387026mr18699715qtr.42.1674195840824; Thu, 19 Jan 2023 22:24:00 -0800 (PST) Received: from auth2-smtp.messagingengine.com (auth2-smtp.messagingengine.com. [66.111.4.228]) by smtp.gmail.com with ESMTPSA id q30-20020a37f71e000000b006ec62032d3dsm13983436qkj.30.2023.01.19.22.23.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Jan 2023 22:24:00 -0800 (PST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailauth.nyi.internal (Postfix) with ESMTP id C783D27C0054; Fri, 20 Jan 2023 01:23:59 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Fri, 20 Jan 2023 01:23:59 -0500 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrudduuddgleejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvdenucfhrhhomhepuehoqhhu nhcuhfgvnhhguceosghoqhhunhdrfhgvnhhgsehgmhgrihhlrdgtohhmqeenucggtffrrg htthgvrhhnpeehudfgudffffetuedtvdehueevledvhfelleeivedtgeeuhfegueeviedu ffeivdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpe gsohhquhhnodhmvghsmhhtphgruhhthhhpvghrshhonhgrlhhithihqdeiledvgeehtdei gedqudejjeekheehhedvqdgsohhquhhnrdhfvghngheppehgmhgrihhlrdgtohhmsehfih igmhgvrdhnrghmvg X-ME-Proxy: Feedback-ID: iad51458e:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 20 Jan 2023 01:23:58 -0500 (EST) Date: Thu, 19 Jan 2023 22:23:56 -0800 From: Boqun Feng To: Wedson Almeida Filho Cc: rust-for-linux@vger.kernel.org, Miguel Ojeda , Alex Gaynor , Gary Guo , =?iso-8859-1?Q?Bj=F6rn?= Roy Baron , linux-kernel@vger.kernel.org Subject: Re: [PATCH 1/5] rust: types: introduce `ScopeGuard` Message-ID: References: <20230119174036.64046-1-wedsonaf@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230119174036.64046-1-wedsonaf@gmail.com> 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: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, Jan 19, 2023 at 02:40:32PM -0300, Wedson Almeida Filho wrote: > This allows us to run some code when the guard is dropped (e.g., > implicitly when it goes out of scope). We can also prevent the > guard from running by calling its `dismiss()` method. > > Signed-off-by: Wedson Almeida Filho > --- > rust/kernel/types.rs | 127 ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 126 insertions(+), 1 deletion(-) > > diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs > index e84e51ec9716..f0ad4472292d 100644 > --- a/rust/kernel/types.rs > +++ b/rust/kernel/types.rs > @@ -2,7 +2,132 @@ > > //! Kernel types. > > -use core::{cell::UnsafeCell, mem::MaybeUninit}; > +use alloc::boxed::Box; > +use core::{ > + cell::UnsafeCell, > + mem::MaybeUninit, > + ops::{Deref, DerefMut}, > +}; > + > +/// Runs a cleanup function/closure when dropped. > +/// > +/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. > +/// > +/// # Examples > +/// > +/// In the example below, we have multiple exit paths and we want to log regardless of which one is > +/// taken: > +/// ``` > +/// # use kernel::ScopeGuard; > +/// fn example1(arg: bool) { > +/// let _log = ScopeGuard::new(|| pr_info!("example1 completed\n")); > +/// > +/// if arg { > +/// return; > +/// } > +/// > +/// pr_info!("Do something...\n"); > +/// } > +/// > +/// # example1(false); > +/// # example1(true); > +/// ``` > +/// > +/// In the example below, we want to log the same message on all early exits but a different one on > +/// the main exit path: > +/// ``` > +/// # use kernel::ScopeGuard; > +/// fn example2(arg: bool) { > +/// let log = ScopeGuard::new(|| pr_info!("example2 returned early\n")); > +/// > +/// if arg { > +/// return; > +/// } > +/// > +/// // (Other early returns...) > +/// > +/// log.dismiss(); > +/// pr_info!("example2 no early return\n"); > +/// } > +/// > +/// # example2(false); > +/// # example2(true); > +/// ``` > +/// > +/// In the example below, we need a mutable object (the vector) to be accessible within the log > +/// function, so we wrap it in the [`ScopeGuard`]: > +/// ``` > +/// # use kernel::ScopeGuard; > +/// fn example3(arg: bool) -> Result { > +/// let mut vec = > +/// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len())); > +/// > +/// vec.try_push(10u8)?; > +/// if arg { > +/// return Ok(()); > +/// } > +/// vec.try_push(20u8)?; > +/// Ok(()) > +/// } > +/// > +/// # assert_eq!(example3(false), Ok(())); > +/// # assert_eq!(example3(true), Ok(())); > +/// ``` > +/// > +/// # Invariants > +/// > +/// The value stored in the struct is nearly always `Some(_)`, except between > +/// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value > +/// will have been returned to the caller. Since [`ScopeGuard::dismiss`] consumes the guard, > +/// callers won't be able to use it anymore. > +pub struct ScopeGuard(Option<(T, F)>); > + > +impl ScopeGuard { > + /// Creates a new guarded object wrapping the given data and with the given cleanup function. > + pub fn new_with_data(data: T, cleanup_func: F) -> Self { > + // INVARIANT: The struct is being initialised with `Some(_)`. > + Self(Some((data, cleanup_func))) > + } > + > + /// Prevents the cleanup function from running and returns the guarded data. > + pub fn dismiss(mut self) -> T { > + // INVARIANT: This is the exception case in the invariant; it is not visible to callers > + // because this function consumes `self`. > + self.0.take().unwrap().0 > + } > +} > + > +impl ScopeGuard<(), Box> { How about `fn(())` here as a placeholder? I.e impl ScopeGuard<(), fn(())> Regards, Boqun > + /// Creates a new guarded object with the given cleanup function. > + pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> { > + ScopeGuard::new_with_data((), move |_| cleanup()) > + } > +} > + > +impl Deref for ScopeGuard { > + type Target = T; > + > + fn deref(&self) -> &T { > + // The type invariants guarantee that `unwrap` will succeed. > + &self.0.as_ref().unwrap().0 > + } > +} > + > +impl DerefMut for ScopeGuard { > + fn deref_mut(&mut self) -> &mut T { > + // The type invariants guarantee that `unwrap` will succeed. > + &mut self.0.as_mut().unwrap().0 > + } > +} > + > +impl Drop for ScopeGuard { > + fn drop(&mut self) { > + // Run the cleanup function if one is still present. > + if let Some((data, cleanup)) = self.0.take() { > + cleanup(data) > + } > + } > +} > > /// Stores an opaque value. > /// > -- > 2.34.1 >