From nobody Fri Nov 14 16:50:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1761924460; cv=none; d=zohomail.com; s=zohoarc; b=LHuR6JbfbOyY0y2XC1pjA7nFNSkiLiVf5OUt7Ysg0lTDZXYcLY1rcLcXCKPNSYxhCn3+6ryruPcxrzBTh58XicYU1LPW4rekUW/lCAVr4jL5joXiMpgPsKEY41Cizq51WZXfhW8JdI29iu2V2q6u0ObhwCaSOTWdXSkRHjLvquA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761924460; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=yq29Dg28MtHToBMDyjMkNHHVvYBx9/maalG2F5iiQUk=; b=mwZZCXDtY6IxQC8V9sHbr69mLM8iJNogN88XPg8gXpPxZuk9U7gWx1M+uIWa0Bel2kI2aifroPBf2otrxuc3z1gOOzNmXnriAhdjKoHMwOW9QVo3zllX8KSf09FeAFbVhPZ8hFWOMXho0uPp8rqcFwiEEeooWRV6AxT2hIKtbfc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1761924460047677.0182946556482; Fri, 31 Oct 2025 08:27:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vEr0s-000158-8i; Fri, 31 Oct 2025 11:26:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0q-000139-Ie for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:00 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0j-0000nw-0R for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:00 -0400 Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-187-y1GqENMbPmi8duaNuuFCkA-1; Fri, 31 Oct 2025 11:25:48 -0400 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-4270a61ec48so2483975f8f.1 for ; Fri, 31 Oct 2025 08:25:48 -0700 (PDT) Received: from [192.168.10.48] ([151.95.110.222]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-429c13f1d4csm3735435f8f.39.2025.10.31.08.25.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Oct 2025 08:25:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1761924349; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yq29Dg28MtHToBMDyjMkNHHVvYBx9/maalG2F5iiQUk=; b=TxQChlmbiftbsEJzfVovzhLVbq/O87A3F08O3LS+Tb4Wmv6afWE9BkHu3sAcM0EiVrAI0w ZZsRv4FDCkrQghABgWXWVXK+uVpQ1aMM3/JSU+DjTp//XZOuhB+A1UyjarjjFEjazwHm+o tsEe5sv3xiLftaxBtS7utxpobCXkMAw= X-MC-Unique: y1GqENMbPmi8duaNuuFCkA-1 X-Mimecast-MFC-AGG-ID: y1GqENMbPmi8duaNuuFCkA_1761924348 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761924347; x=1762529147; 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=yq29Dg28MtHToBMDyjMkNHHVvYBx9/maalG2F5iiQUk=; b=L7ViMiAogBrE7lnZeOF5sgPQTm1gIGwEtwrRdkp/ezygYhvalamKyBETIs7vF3xg3g DxT3GegYf1gUeu/ObShN8NQ3WRFkRKslJyBzrUdcWvUlBS1uUKBbrwhYL5uJpvQ3aBGI W0dZal8Y6zIwDumGdWmw6O56/NDw53vxTC9us0LxihuC+cwz3f0G3t4I50Fdi/UlHGxy OFSW4PgSs7n4Sd8sYUkCHEppP0527uk+uirPITLX2o2eQFqhwrp09z2xOwrI8/+UDPGS 7xPE3SPoFBgT2XyKJ2nhrjf/EZXRn/uMPqiWvl0bPnWEFzj83ata3g+pekLNYVPgncNm HNzg== X-Gm-Message-State: AOJu0YxtO3E3dMASxPWc7tCt4MOTIUDfzEtvIGp/6SQ9qc8oIA6ATaz8 kF1mxf/0OFTPcgWB2iClvVTgElepg4+435DCnzCMx3xvIOZ9QSpOtssdr2FrOQDVyA7gq11pNnG 28y0LLWDwQlvHxExymQ+VdNTSjwOXFq1VxwejtR7cZBeJTbu74JS5Ict3V9aqdvvemxa9Yxq9eR sSAY8Qy2/O5ca95JxDa9gPaSLzEk1sOdF/HnBheht8 X-Gm-Gg: ASbGncuVv8WA+rAvSQvzinB5yIDA6Cm1lt8Z+jc5oJreolStTDBAy4z+DX6irTvSXMF 9bNU72o6KtMRgPejUlEsA0g63qcC6qOh+t+qSJ+jJnsZN8YO0EaKrpgX2V/WbXDu/bbQrJeCxZK 0O1pw4N/m98ieCvvYQSqae+ukjjLhB/oogGDBteFA9pB/RbNgpYNpk98U7Gh0Kc7aSbNclo7ST/ TIXiXMzCmcBtsR2gmXPocY1OU4vg6rlvbr+SY8aOQ+btmUbARzmpaTbiJdSYVGmEgJrPeLTsSlh O2WRKS7KjqQ5B5LVbPVj4JkQV5eOVqAm2gIi04yotj0LXllOrCfcLGdjiuCd6XpKPr4iptuRlY2 o/H50snTMiaXedVIWrb4YLff/ey8pPBFLL45co34n3CCqNjDMw58T86RL3mbwwaeAHKqbQCNr8v b1i0X5 X-Received: by 2002:a05:6000:178d:b0:429:b6e2:1ecf with SMTP id ffacd0b85a97d-429bd682973mr3607042f8f.22.1761924346537; Fri, 31 Oct 2025 08:25:46 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG+AE6S2+Hnk6TlxexEo9pNzi7wHPxmlDA3dLqnAnfopUDJHyzaRgkMPQVjDKCi6dc3ADB8/A== X-Received: by 2002:a05:6000:178d:b0:429:b6e2:1ecf with SMTP id ffacd0b85a97d-429bd682973mr3607011f8f.22.1761924345963; Fri, 31 Oct 2025 08:25:45 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 1/4] rust/util: add ensure macro Date: Fri, 31 Oct 2025 16:25:36 +0100 Message-ID: <20251031152540.293293-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251031152540.293293-1-pbonzini@redhat.com> References: <20251031152540.293293-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, T_SPF_TEMPERROR=0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1761924469250158500 Content-Type: text/plain; charset="utf-8" The macro is similar to anyhow::ensure but uses QEMU's variation on anyhow::Error. It can be used to easily check a condition and format an error message. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/timer/hpet/src/device.rs | 21 ++++++---- rust/hw/timer/hpet/src/fw_cfg.rs | 7 ++-- rust/util/src/error.rs | 71 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 13 deletions(-) diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/devi= ce.rs index 23f2eefd1cd..3564aa79c6e 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -25,7 +25,10 @@ bindings::{address_space_memory, address_space_stl_le, hwaddr}, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSP= ECIFIED, }; -use util::timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}; +use util::{ + ensure, + timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, +}; =20 use crate::fw_cfg::HPETFwConfig; =20 @@ -728,14 +731,14 @@ fn post_init(&self) { } =20 fn realize(&self) -> util::Result<()> { - if self.num_timers < HPET_MIN_TIMERS || self.num_timers > HPET_MAX= _TIMERS { - Err(format!( - "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HP= ET_MAX_TIMERS}" - ))?; - } - if self.int_route_cap =3D=3D 0 { - Err("hpet.hpet-intcap property not initialized")?; - } + ensure!( + (HPET_MIN_TIMERS..=3DHPET_MAX_TIMERS).contains(&self.num_timer= s), + "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_M= AX_TIMERS}" + ); + ensure!( + self.int_route_cap !=3D 0, + "hpet.hpet-intcap property not initialized" + ); =20 self.hpet_id.set(HPETFwConfig::assign_hpet_id()?); =20 diff --git a/rust/hw/timer/hpet/src/fw_cfg.rs b/rust/hw/timer/hpet/src/fw_c= fg.rs index bb4ea8909ad..777fc8ef45e 100644 --- a/rust/hw/timer/hpet/src/fw_cfg.rs +++ b/rust/hw/timer/hpet/src/fw_cfg.rs @@ -5,6 +5,7 @@ use std::ptr::addr_of_mut; =20 use common::Zeroable; +use util::{self, ensure}; =20 /// Each `HPETState` represents a Event Timer Block. The v1 spec supports /// up to 8 blocks. QEMU only uses 1 block (in PC machine). @@ -36,7 +37,7 @@ unsafe impl Zeroable for HPETFwConfig {} }; =20 impl HPETFwConfig { - pub(crate) fn assign_hpet_id() -> Result { + pub(crate) fn assign_hpet_id() -> util::Result { assert!(bql::is_locked()); // SAFETY: all accesses go through these methods, which guarantee // that the accesses are protected by the BQL. @@ -47,9 +48,7 @@ pub(crate) fn assign_hpet_id() -> Result { fw_cfg.count =3D 0; } =20 - if fw_cfg.count =3D=3D 8 { - Err("Only 8 instances of HPET are allowed")?; - } + ensure!(fw_cfg.count !=3D 8, "Only 8 instances of HPET are allowed= "); =20 let id: usize =3D fw_cfg.count.into(); fw_cfg.count +=3D 1; diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index bfa5a8685bc..2a57c7fd5fd 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -86,6 +86,19 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } =20 +impl From> for Error { + #[track_caller] + fn from(msg: Cow<'static, str>) -> Self { + let location =3D panic::Location::caller(); + Error { + msg: Some(msg), + cause: None, + file: location.file(), + line: location.line(), + } + } +} + impl From for Error { #[track_caller] fn from(msg: String) -> Self { @@ -126,6 +139,17 @@ fn from(error: anyhow::Error) -> Self { } =20 impl Error { + #[track_caller] + #[doc(hidden)] + pub fn format(args: fmt::Arguments) -> Self { + if let Some(msg) =3D args.as_str() { + Self::from(msg) + } else { + let msg =3D fmt::format(args); + Self::from(msg) + } + } + /// Create a new error, prepending `msg` to the /// description of `cause` #[track_caller] @@ -311,6 +335,53 @@ unsafe fn cloned_from_foreign(c_error: *const bindings= ::Error) -> Self { } } =20 +/// Ensure that a condition is true, returning an error if it is false. +/// +/// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Resul= t`]. +/// If the condition evaluates to `false`, the macro returns early with an= error +/// constructed from the provided message. +/// +/// # Examples +/// +/// ``` +/// # use util::{ensure, Result}; +/// # fn check_positive(x: i32) -> Result<()> { +/// ensure!(x > 0, "value must be positive"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use util::{ensure, Result}; +/// # const MIN: i32 =3D 123; +/// # const MAX: i32 =3D 456; +/// # fn check_range(x: i32) -> Result<()> { +/// ensure!( +/// x >=3D MIN && x <=3D MAX, +/// "{} not between {} and {}", +/// x, +/// MIN, +/// MAX +/// ); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! ensure { + ($cond:expr, $fmt:literal, $($arg:tt)*) =3D> { + if !$cond { + let e =3D $crate::Error::format(format_args!($fmt, $($arg)*)); + return $crate::Result::Err(e); + } + }; + ($cond:expr, $err:expr $(,)?) =3D> { + if !$cond { + let s =3D ::std::borrow::Cow::<'static, str>::from($err); + return $crate::Result::Err(s.into()); + } + }; +} + #[cfg(test)] mod tests { use std::ffi::CStr; --=20 2.51.1 From nobody Fri Nov 14 16:50:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1761924479; cv=none; d=zohomail.com; s=zohoarc; b=QAWCDWZcKNH8te/1jwRnNLghr8PdcCETaZY1Fm02ADI7XD6eLJeUrvvW0HjE+ZxfZDA9BtE/kG4wqWHuEcrd2gRVdduHc3JWdf+5TjxF3K9JZPITSsta1hZ52G4G7oqQrBvhA4BGVUM868ayhMHAX6YEu6uSxT+4HAdHS85xaqM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761924479; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=XWOdxSuJQXd9jwTAwyQvGMryTPeaJlfg/6hUIbTKrr8=; b=DCp6ahb5ZusUxGVb1qrnM6kkLQDgj6n3P+G31Ngq/hORQHjjTm0bgRj2oJTWCOoA5FortipJurx+WTxi1OUTOqMGQIElKQi0+szyLR5XtVMUec7AlK6EYoyDv2K4A/Jd0SSM0GN4eZw+GHpXnkJvQQPETHjBlZ+JpgYqiuQz4nw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1761924479337644.0951820416725; Fri, 31 Oct 2025 08:27:59 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vEr0y-000197-Mc; Fri, 31 Oct 2025 11:26:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0w-000180-Pw for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0o-0000oR-JI for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:06 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-213-IaVXdanwM9mPX41edaW1FA-1; Fri, 31 Oct 2025 11:25:51 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-46e47d14dceso13689795e9.2 for ; Fri, 31 Oct 2025 08:25:51 -0700 (PDT) Received: from [192.168.10.48] ([151.95.110.222]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4773c48daa0sm2089525e9.3.2025.10.31.08.25.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Oct 2025 08:25:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1761924353; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XWOdxSuJQXd9jwTAwyQvGMryTPeaJlfg/6hUIbTKrr8=; b=FnL+YFPQnSvM+rmqfjWGsdjLzhOgvEpzyBkfV8yesLo1U8OoyOi1lLMx50koOW+CQl1ERr Mg18rWK3k4qJ0nmwDJiMc5NunVblhUVHw3hv1Q+kimhPtUYJjoFmTV8Rxb4rsDl3QRjVCj HxAHlr2Q3vmLM0UaAPPUVjhLI+d2VoY= X-MC-Unique: IaVXdanwM9mPX41edaW1FA-1 X-Mimecast-MFC-AGG-ID: IaVXdanwM9mPX41edaW1FA_1761924350 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761924349; x=1762529149; 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=XWOdxSuJQXd9jwTAwyQvGMryTPeaJlfg/6hUIbTKrr8=; b=YisopkbtI131FDlRLTjsJ1F4QGe/rOxZGz0dc4hL9Sj3ytLp0NeALUAoB7mK4E4vhC 477gga5DPDXa3EEwSftxvZ6oaehYtu/+tpiBMvIxhE3GZv/8sLS05fiTdxoN3GFBMaQD dMog/AIVw8RywrymUM569aqGTV99nw2dPooyPIrarGaSw96MOFzsK8CQwyC1jBoINI86 fsBjV0vWVAyrHSdAlKl5+1OoXyo0IxF2nMf4BgPrVD8XYd2FcQN/aDIZUOs22/UpqqG3 7jLP845aNCj2iwwyRqOurSCc4vmVYIvxYvEWm4GYadZ1WNpiSddIv/wiDxV3hbvoIelV wk3A== X-Gm-Message-State: AOJu0Yx8yxfyCzm1xZIYLmdyou6x48E9OHQPSQ8GjirMotSh9rrt7kgk kWuL1HDB3dMrqUWS/fVFQBMco15NqD3Lu7q8vRg1k4PH1FD5dtKVcxbeoY9oWIeRG9co1OfcbSn Y04n0vwfMUOuY49ygK/VbmWOaZp+1VcDEuOZ7ThrCzPCailg/WWDR7t4+txbKctUJ2nQCZRTdE/ 5d9ydOlR7GwZZv8/gDsYTVYoNOaoDYoq+EFxhVihPL X-Gm-Gg: ASbGncvQ4skOTx/EJqJSbXzmkXYKJjHJlNlJ1aD77/wFIwoY4wTNr0uKB34XxhFKjLS C1ockoFeVmZsBVPivRtjCDJM7DmwLldSrkhUEq+EepL7VtFBdwskb38kl8xdTEubnQuZlWuzvRZ b3cIqGwZCoXBfUgEjgqN2GyF+Puy9gn2pdl1eSuj8328e3LqT3mYeEUF+4HX6RBhzwHkl+choWJ qgLENj9zDXEubuwVQC/DD1qk3MSgpaiFtRxOPWr9YEuNvZpIvMUIofT4FVXfdBk31teLI8rIxlf vKeI6fu6oJvB1rY1Bs2hv2xfPyvK3A95O76JVQoYExNqFTmFrDmV1z3dD00588nNmlawLr7Roth X1MUJ++dTCsHc792B+aBf4jlUCy6IEKp+6pd261QKuaR5vGcGy0GksduNqOw4VPjdXQSXKNz1dB +zLCSB X-Received: by 2002:a05:600c:530f:b0:477:1bb6:17de with SMTP id 5b1f17b1804b1-477308be7a8mr38543955e9.30.1761924349376; Fri, 31 Oct 2025 08:25:49 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHbfH1Ib1RMX6MlVQQ2pbfK8DgAS7484UnHe8O958VBsgNQ4OSTKnM93Eogb5CR+yfxi/+yaw== X-Received: by 2002:a05:600c:530f:b0:477:1bb6:17de with SMTP id 5b1f17b1804b1-477308be7a8mr38543595e9.30.1761924348734; Fri, 31 Oct 2025 08:25:48 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 2/4] rust/util: use anyhow's native chaining capabilities Date: Fri, 31 Oct 2025 16:25:37 +0100 Message-ID: <20251031152540.293293-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251031152540.293293-1-pbonzini@redhat.com> References: <20251031152540.293293-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, T_SPF_TEMPERROR=0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1761924481309158500 Content-Type: text/plain; charset="utf-8" This simplifies conversions, making it possible to convert any error into a QEMU util::Error with ".into()" (and therefore with "?"). The cost is having a separate constructor for when the error is a simple string, but that is made easier by the ensure! macro. If necessary, another macro similar to "anyhow!" can be returned, but for now there is no need for that. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/util/src/error.rs | 160 +++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 101 deletions(-) diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 2a57c7fd5fd..11b574ca593 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -38,6 +38,7 @@ borrow::Cow, ffi::{c_char, c_int, c_void, CStr}, fmt::{self, Display}, + ops::Deref, panic, ptr, }; =20 @@ -49,118 +50,85 @@ =20 #[derive(Debug)] pub struct Error { - msg: Option>, - /// Appends the print string of the error to the msg if not None - cause: Option, + cause: anyhow::Error, file: &'static str, line: u32, } =20 -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.cause.as_ref().map(AsRef::as_ref) - } +impl Deref for Error { + type Target =3D anyhow::Error; =20 - #[allow(deprecated)] - fn description(&self) -> &str { - self.msg - .as_deref() - .or_else(|| self.cause.as_deref().map(std::error::Error::descr= iption)) - .expect("no message nor cause?") + fn deref(&self) -> &Self::Target { + &self.cause } } =20 impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut prefix =3D ""; - if let Some(ref msg) =3D self.msg { - write!(f, "{msg}")?; - prefix =3D ": "; - } - if let Some(ref cause) =3D self.cause { - write!(f, "{prefix}{cause}")?; - } else if prefix.is_empty() { - panic!("no message nor cause?"); - } - Ok(()) + Display::fmt(&format_args!("{:#}", self.cause), f) } } =20 -impl From> for Error { +impl From for Error +where + anyhow::Error: From, +{ #[track_caller] - fn from(msg: Cow<'static, str>) -> Self { - let location =3D panic::Location::caller(); - Error { - msg: Some(msg), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From for Error { - #[track_caller] - fn from(msg: String) -> Self { - let location =3D panic::Location::caller(); - Error { - msg: Some(Cow::Owned(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From<&'static str> for Error { - #[track_caller] - fn from(msg: &'static str) -> Self { - let location =3D panic::Location::caller(); - Error { - msg: Some(Cow::Borrowed(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From for Error { - #[track_caller] - fn from(error: anyhow::Error) -> Self { - let location =3D panic::Location::caller(); - Error { - msg: None, - cause: Some(error), - file: location.file(), - line: location.line(), - } + fn from(src: E) -> Self { + Self::new(anyhow::Error::from(src)) } } =20 impl Error { + /// Create a new error from an [`anyhow::Error`]. + /// + /// This wraps the error with QEMU's location tracking information. + /// Most code should use the `?` operator instead of calling this dire= ctly. + #[track_caller] + pub fn new(cause: anyhow::Error) -> Self { + let location =3D panic::Location::caller(); + Self { + cause, + file: location.file(), + line: location.line(), + } + } + + /// Create a new error from a string message. + /// + /// This is a convenience wrapper around [`Error::new`] for simple str= ing + /// errors. Most code should use the [`ensure!`](crate::ensure) macro + /// instead of calling this directly. + #[track_caller] + pub fn msg(src: impl Into>) -> Self { + Self::new(anyhow::Error::msg(src.into())) + } + #[track_caller] #[doc(hidden)] + #[inline(always)] pub fn format(args: fmt::Arguments) -> Self { - if let Some(msg) =3D args.as_str() { - Self::from(msg) - } else { - let msg =3D fmt::format(args); - Self::from(msg) - } + // anyhow::Error::msg will allocate anyway, might as well let fmt:= :format doit. + let msg =3D fmt::format(args); + Self::new(anyhow::Error::msg(msg)) } =20 /// Create a new error, prepending `msg` to the /// description of `cause` #[track_caller] pub fn with_error(msg: impl Into>, cause: impl Into<= anyhow::Error>) -> Self { - let location =3D panic::Location::caller(); - Error { - msg: Some(msg.into()), - cause: Some(cause.into()), - file: location.file(), - line: location.line(), + fn do_with_error( + msg: Cow<'static, str>, + cause: anyhow::Error, + location: &'static panic::Location<'static>, + ) -> Error { + Error { + cause: cause.context(msg), + file: location.file(), + line: location.line(), + } } + do_with_error(msg.into(), cause.into(), panic::Location::caller()) } =20 /// Consume a result, returning `false` if it is an error and @@ -326,8 +294,7 @@ unsafe fn cloned_from_foreign(c_error: *const bindings:= :Error) -> Self { }; =20 Error { - msg: FromForeign::cloned_from_foreign(error.msg), - cause: None, + cause: anyhow::Error::msg(String::cloned_from_foreign(erro= r.msg)), file: file.unwrap(), line: error.line as u32, } @@ -376,8 +343,8 @@ macro_rules! ensure { }; ($cond:expr, $err:expr $(,)?) =3D> { if !$cond { - let s =3D ::std::borrow::Cow::<'static, str>::from($err); - return $crate::Result::Err(s.into()); + let e =3D $crate::Error::msg($err); + return $crate::Result::Err(e); } }; } @@ -416,19 +383,10 @@ unsafe fn error_get_pretty<'a>(local_err: *mut bindin= gs::Error) -> &'a CStr { unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) } } =20 - #[test] - #[allow(deprecated)] - fn test_description() { - use std::error::Error; - - assert_eq!(super::Error::from("msg").description(), "msg"); - assert_eq!(super::Error::from("msg".to_owned()).description(), "ms= g"); - } - #[test] fn test_display() { - assert_eq!(&*format!("{}", Error::from("msg")), "msg"); - assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg")), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg".to_owned())), "msg"); assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg"); =20 assert_eq!( @@ -445,7 +403,7 @@ fn test_bool_or_propagate() { assert!(Error::bool_or_propagate(Ok(()), &mut local_err)); assert_eq!(local_err, ptr::null_mut()); =20 - let my_err =3D Error::from("msg"); + let my_err =3D Error::msg("msg"); assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err)= ); assert_ne!(local_err, ptr::null_mut()); assert_eq!(error_get_pretty(local_err), c"msg"); @@ -462,7 +420,7 @@ fn test_ptr_or_propagate() { assert_eq!(String::from_foreign(ret), "abc"); assert_eq!(local_err, ptr::null_mut()); =20 - let my_err =3D Error::from("msg"); + let my_err =3D Error::msg("msg"); assert_eq!( Error::ptr_or_propagate(Err::(my_err), &mut loc= al_err), ptr::null_mut() --=20 2.51.1 From nobody Fri Nov 14 16:50:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1761924456; cv=none; d=zohomail.com; s=zohoarc; b=cEDQP1zWlyY8M39lQ9WzJrseKxKiBwe+piWWzgAJuyFCAP8Zrdey8BhtpPnHVcUOheE73SxuQfYzzNwy5w9LAECBMrST76orTthUTjF2JVRNmPICwfUEpEJTwliyvnMpVTzC6O9mvat/cOXkZxdywNxJjLEe2HM2VRsrns6Osr8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761924456; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=rhztnyZ1fNBhV8SQSbp7sZrMppapud0hpLsKWcngaNE=; b=bs5aA5lit3S9O6DGvwNCI+bFHfqj0VR9+ZAFfjRsJtwm4gywcMBHr/kvYmPouqcBRfIDyLEUI39UqnfAIq8F7N/w0FekyhyMShHfu/AxqNfbBeqYa/veqQxUMVPZs5fo/v3x764aXNVZLpmIwu+Yey6RBjLuCMrvUoL493UaZlI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 176192445641260.73942460617343; Fri, 31 Oct 2025 08:27:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vEr0w-00017h-OO; Fri, 31 Oct 2025 11:26:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0v-00016c-1x for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:05 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0p-0000or-G9 for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:04 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-490-F-V3xQEzMXWMHI5ak7oTtg-1; Fri, 31 Oct 2025 11:25:53 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-40cfb98eddbso1680755f8f.0 for ; Fri, 31 Oct 2025 08:25:53 -0700 (PDT) Received: from [192.168.10.48] ([151.95.110.222]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-429c13e16d8sm4205103f8f.31.2025.10.31.08.25.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Oct 2025 08:25:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1761924355; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rhztnyZ1fNBhV8SQSbp7sZrMppapud0hpLsKWcngaNE=; b=ZmWW5RV0XiR4Eu0slUq5BNW8NctNhN6pJCkXIDebilj7dAlP9+0UBnbfWgQ2yI7xp5nPGe 0X3XpCaNsb7ttvhAs+8GnLxd/0o2IwMP9fOHV8dGIbQQQPZDmmnrZHtVprltvrB/r9aqSB 8U6okmeL82qO+EaqekYq3mFGh8qt+H4= X-MC-Unique: F-V3xQEzMXWMHI5ak7oTtg-1 X-Mimecast-MFC-AGG-ID: F-V3xQEzMXWMHI5ak7oTtg_1761924353 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761924352; x=1762529152; 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=rhztnyZ1fNBhV8SQSbp7sZrMppapud0hpLsKWcngaNE=; b=n6emJmQalzlJOFUW/mHr2Tv2RYjXbOeq5tyrzuvuvbyWTxlaPwoCbGIPWNIbT7aYUU cYFOGYLxFSdLxRGxWFBHiv2EHZ6ArxwlaAQ+38qhUYIMuhkansxEet86P+m2pQhTUKCH JQ5yS8Ucwotvz7zldTOwv92AXbzOk5S8m5ogHH9HymQhTFO/x8Msb52Rq3EausTpNprz DByM4cL8nl/j139J2XPvLZ8mXgQK34xfdKp6wyUKDFzK4sYMuPLYkZulGKayf6pV3g7D US+icf7yz6hRGuTEffYZTUr6hZTzuV7ifZOOM83yoQdQGlimFhqTYAJx5+5vywJYksAE uBxw== X-Gm-Message-State: AOJu0Yw/Rsy7BL5MOpn8YYEBez99ewY/3o18GnLXNzliaOJMDEFgxGS1 cjQkJ4Syx6f+ahMIgJ44vS3JCuaBF6zrs5YdQVMlr45y9GNKvt3HXWNef7+kdFec5ykJIZHxziJ FZYG12w/CEAbE+4qFqb1Cv9/NFyT2Chy3RK6w9KvBpa59NJvDeUlM1XNvAUbpiJL8CyLCQiwWyZ kRfGUekcAPo24LoTfKQB+tSI+CkAo5lg78Dn5uCzME X-Gm-Gg: ASbGnct1oIBiChlTAQaf8cTt+gZH80ReKVMB2YUrHxCBO37zep5WapQ4lEKNXgaHyKD hmqZ0wMQSq3bXGnbIM4WTZSYrazMvhjoSW52ZvITN+YU8TSXZa/0PdC1N+XQMtRbSk+oPjg/5Ha fbmWorIH9b4p7dHs4J0d/nJj7M0YWJlPJ/ByrKMuqQYIKSZfHjmz6qY7pc/F/8bCPrTxVi7bSU5 kzsTYxSMwUCO1cHKugFoh4PEoqjmM//72f4Yew73ZvD0dqxAKk3gM897NTFvCIfNPpNqQcs5ShD 1GxVeFZHsW+mE9I1klfMNJoLrGrO492Vw3MbI3DyNSZ85fwRPDfiLGyQRe0TXXumojdsdfhBplV +SojYqJ/nocn0SwOsvAWvtAa1i4DJ8HYbzA2d0EDDC1fdq3AUsIrgzFnIklcu3LLNlcSLEZRh8w OCXKc3 X-Received: by 2002:adf:e193:0:b0:425:86da:325f with SMTP id ffacd0b85a97d-429bcda2109mr4357390f8f.27.1761924352054; Fri, 31 Oct 2025 08:25:52 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHB0Wh7Dczto4sCtlbVCCZihcE//My0ye+xILxV8m5LMg79nMkdJ71mzBsBCrDYktng7KMZPQ== X-Received: by 2002:adf:e193:0:b0:425:86da:325f with SMTP id ffacd0b85a97d-429bcda2109mr4357357f8f.27.1761924351572; Fri, 31 Oct 2025 08:25:51 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 3/4] rust/util: replace Error::err_or_unit/err_or_else with Error::with_errp Date: Fri, 31 Oct 2025 16:25:38 +0100 Message-ID: <20251031152540.293293-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251031152540.293293-1-pbonzini@redhat.com> References: <20251031152540.293293-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1761924458960154100 Content-Type: text/plain; charset="utf-8" Introduce a simpler function that hides the creation of the Error**. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/util/src/error.rs | 52 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 11b574ca593..346577e2e53 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -14,8 +14,7 @@ //! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to = build //! a C return value while also propagating an error condition //! -//! * [`err_or_else`](crate::Error::err_or_else) and -//! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `R= esult` +//! * [`with_errp`](crate::Error::with_errp) can be used to build a `Resul= t` //! //! This module is most commonly used at the boundary between C and Rust c= ode; //! other code will usually access it through the @@ -213,35 +212,21 @@ pub unsafe fn propagate(self, errp: *mut *mut binding= s::Error) { } } =20 - /// Convert a C `Error*` into a Rust `Result`, using - /// `Ok(())` if `c_error` is NULL. Free the `Error*`. + /// Pass a C `Error*` to the closure, and convert the result + /// (either the return value of the closure, or the error) + /// into a Rust `Result`. /// /// # Safety /// - /// `c_error` must be `NULL` or valid; typically it was initialized - /// with `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()>= { - // SAFETY: caller guarantees c_error is valid - unsafe { Self::err_or_else(c_error, || ()) } - } + /// One exit from `f`, `c_error` must be unchanged or point to a + /// valid C [`struct Error`](bindings::Error). + pub unsafe fn with_errp T>(= f: F) -> Result { + let mut c_error: *mut bindings::Error =3D ptr::null_mut(); =20 - /// Convert a C `Error*` into a Rust `Result`, calling `f()` to - /// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`. - /// - /// # Safety - /// - /// `c_error` must be `NULL` or point to a valid C [`struct - /// Error`](bindings::Error); typically it was initialized with - /// `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_else T>( - c_error: *mut bindings::Error, - f: F, - ) -> Result { - // SAFETY: caller guarantees c_error is valid - let err =3D unsafe { Option::::from_foreign(c_error) }; - match err { - None =3D> Ok(f()), - Some(err) =3D> Err(err), + // SAFETY: guaranteed by the postcondition of `f` + match (f(&mut c_error), unsafe { c_error.into_native() }) { + (result, None) =3D> Ok(result), + (_, Some(err)) =3D> Err(err), } } } @@ -432,13 +417,16 @@ fn test_ptr_or_propagate() { } =20 #[test] - fn test_err_or_unit() { + fn test_with_errp() { unsafe { - let result =3D Error::err_or_unit(ptr::null_mut()); - assert_match!(result, Ok(())); + let result =3D Error::with_errp(|_errp| true); + assert_match!(result, Ok(true)); =20 - let err =3D error_for_test(c"msg"); - let err =3D Error::err_or_unit(err.into_inner()).unwrap_err(); + let err =3D Error::with_errp(|errp| { + *errp =3D error_for_test(c"msg").into_inner(); + false + }) + .unwrap_err(); assert_eq!(&*format!("{err}"), "msg"); } } --=20 2.51.1 From nobody Fri Nov 14 16:50:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1761924463; cv=none; d=zohomail.com; s=zohoarc; b=WYKtVeqpHEN3/DGvCVal9PR1smXoz/wHi48ovbrKieHwleQBWqLFRPYw7p0ti8Hh1/jIPgDvnZXecF9JAnN1oKgggQUKEwqsst8HZorwTEW27KUwHXxIhvAGXPg+igBdnyHW1hg45tzx0l+8AWbaluhMFyvmR1/yIzspha7h6RM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761924463; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=y54ade2XN2F/JSqNfaUsi9myG2OIy0vlK46SL95guqc=; b=M6UvKMptXfSB1hTjE1Zjt652y2EevolvbHgHp+M6rhlyakudHDz+/PhtqsQPBvsEuzO2bMoAYb8ts/4LwC7WsGZS+l9YzHVh9hMw1iOHaqresSjHW2MgyGSB8dLLrcQ/Ly+yW+rl0EC8SqQgjtlJETgV2LPxdiC/H3himtj9HaU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1761924463548557.4589163650685; Fri, 31 Oct 2025 08:27:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vEr15-0001CU-G1; Fri, 31 Oct 2025 11:26:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr12-0001Ba-Hs for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:12 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vEr0u-0000pK-0h for qemu-devel@nongnu.org; Fri, 31 Oct 2025 11:26:12 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-388-q2KmYUX1M5CUmdEw9GPd0Q-1; Fri, 31 Oct 2025 11:25:56 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4770e0910e4so16165825e9.0 for ; Fri, 31 Oct 2025 08:25:56 -0700 (PDT) Received: from [192.168.10.48] ([151.95.110.222]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4773c383ba6sm2721745e9.10.2025.10.31.08.25.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Oct 2025 08:25:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1761924358; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y54ade2XN2F/JSqNfaUsi9myG2OIy0vlK46SL95guqc=; b=XZ2FIXtPZYzGwdJONG8VbOTw9OcYNEeXNaWhgMtwIpZbOCY2vmDQNDXLkJXjZD+TPTtZfC Pdz5TFsMpYjgu+23WuPnV2vfgIxxSwNlYJkp1dBhwlc/0+ZyMWXLkWU0FOI0jFZczF9+yV anMfkhxziRqZ+Ixmo0078Oyg66Xyb+8= X-MC-Unique: q2KmYUX1M5CUmdEw9GPd0Q-1 X-Mimecast-MFC-AGG-ID: q2KmYUX1M5CUmdEw9GPd0Q_1761924355 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761924354; x=1762529154; 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=y54ade2XN2F/JSqNfaUsi9myG2OIy0vlK46SL95guqc=; b=b4i65MEi/GVm3Hii/GBFt/9p77h0Vx4HRqqS1mGth//saMtCzwp4RKB5gVxZdbclWA 14hrJtNQUn96SIVRtJqTZBz2t4rRsQB78BrT6GlLi0qUKWf8Sx4HoW3IzwToqnSPDkNC aGT42oBJbaDDf5eDUCP30LzGFXp9VsMWX7GsNaDWa79PJjfpTDot4MdNYjKUveUhZ5wx fk1GnGcB50gxP+y8BOMDGBO8pFIlY/LShUPNnvt+bcNX2sprPkF6A2TJnkApZGVEl3X4 pIivRieLx9nN9HPIfhy5ToK5hvLHWqIrEeERQ0/yWB8WfT3QRo5rsIBKdjyN1fBDyqTn 1yxA== X-Gm-Message-State: AOJu0YzirojPl83kbdoQ7eAZhbzQXOsykTKKMGKSa4BrAXiNPGPfw/M/ EC3T5hDoa2X+Ut65UPI/vs8eLGqy0iJOtZdly/g5IUEKfTn37jlTo28oYofQ6H/DUcrG1YoS1UN bse+Ak/BCyFKXx7KyuqBQfBWPgDAlBFR/JODLL5Q5Qo0AWpzasC234XxyzCdhbMI4xAVRJuOrh8 hNHTCEfkgvCBdlObl7JNW+IIyHipLLxoL70pj/CJ08 X-Gm-Gg: ASbGncufGctfktWhJR0VfSyvrlEjzjH+FyDgGK+bpp1JNvBH7z/puTY/DdlyH/zdaP2 TaFq7yuc8vxS/o8XU260UtucmP21IqIzLO9g8t9MI4yNozscjx7vMrFpKaB01yQ4SVCIPLWno4O P1YSmcF+V6GU/b20Dnen+87HyJtZmn8EH495kvOpVOzdYdjz4YmxFD/RRLVMXNXX3nXjw4JPq3r Uhn7NC4pO8QcitUc8sIjpoq3V78ftM31hpwdSPPRA6VIRtubDmEpm30B9si9hgI3MEEYA9eulm1 KC6/MuX+4gfObESJn/M2uP7UcnHYX0+nzNJPcm3uWqknUPFuoXXXPVoOOic3dRI9B1+lupY8/iY e4cQE+UsHm4vaysrW3VlsTQ3XduOWMY5BbfG2T11Dz6rbA6lXByxOsGed3vwtNCZ202WrenoRZ5 jZMkk7 X-Received: by 2002:a05:600c:8b32:b0:46e:37af:f90e with SMTP id 5b1f17b1804b1-4773bfd5c53mr4646815e9.6.1761924354497; Fri, 31 Oct 2025 08:25:54 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHiF9cLOwqTbhei6ZD8E5j2VEgtk6DkFVBUlIx/9wGnm5I0w+yDV9H7hne6mXSLPf5FKO68nA== X-Received: by 2002:a05:600c:8b32:b0:46e:37af:f90e with SMTP id 5b1f17b1804b1-4773bfd5c53mr4646495e9.6.1761924354023; Fri, 31 Oct 2025 08:25:54 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 4/4] rust: pull error_fatal out of SysbusDeviceMethods::sysbus_realize Date: Fri, 31 Oct 2025 16:25:39 +0100 Message-ID: <20251031152540.293293-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251031152540.293293-1-pbonzini@redhat.com> References: <20251031152540.293293-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1761924473054158500 Content-Type: text/plain; charset="utf-8" Return a Result<()> from the method, and "unwrap" it into error_fatal in the caller. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 4 ++-- rust/hw/core/src/sysbus.rs | 13 ++++++------- rust/util/src/error.rs | 31 ++++++++++++++++++++++++++++++- rust/util/src/lib.rs | 2 +- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/devi= ce.rs index 5e9b13fdf92..26be6ef57f2 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -17,7 +17,7 @@ }; use qom::{prelude::*, ObjectImpl, Owned, ParentField, ParentInit}; use system::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder= }; -use util::{log::Log, log_mask_ln}; +use util::{ResultExt, log::Log, log_mask_ln}; =20 use crate::registers::{self, Interrupt, RegisterOffset}; =20 @@ -697,7 +697,7 @@ pub fn post_load(&self, _version_id: u8) -> Result<(), = migration::InvalidError> let chr =3D unsafe { Owned::::from(&*chr) }; dev.prop_set_chr("chardev", &chr); } - dev.sysbus_realize(); + dev.sysbus_realize().unwrap_fatal(); dev.mmio_map(0, addr); dev.connect_irq(0, &irq); =20 diff --git a/rust/hw/core/src/sysbus.rs b/rust/hw/core/src/sysbus.rs index 282315fce99..68165e89295 100644 --- a/rust/hw/core/src/sysbus.rs +++ b/rust/hw/core/src/sysbus.rs @@ -4,12 +4,13 @@ =20 //! Bindings to access `sysbus` functionality from Rust. =20 -use std::{ffi::CStr, ptr::addr_of_mut}; +use std::ffi::CStr; =20 pub use bindings::SysBusDeviceClass; use common::Opaque; use qom::{prelude::*, Owned}; use system::MemoryRegion; +use util::{Error, Result}; =20 use crate::{ bindings, @@ -107,14 +108,12 @@ fn connect_irq(&self, id: u32, irq: &Owned)= { } } =20 - fn sysbus_realize(&self) { - // TODO: return an Error + fn sysbus_realize(&self) -> Result<()> { assert!(bql::is_locked()); unsafe { - bindings::sysbus_realize( - self.upcast().as_mut_ptr(), - addr_of_mut!(util::bindings::error_fatal), - ); + Error::with_errp(|errp| { + bindings::sysbus_realize(self.upcast().as_mut_ptr(), errp); + }) } } } diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 346577e2e53..4edceff42f3 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -38,7 +38,8 @@ ffi::{c_char, c_int, c_void, CStr}, fmt::{self, Display}, ops::Deref, - panic, ptr, + panic, + ptr::{self, addr_of_mut}, }; =20 use foreign::{prelude::*, OwnedPointer}; @@ -231,6 +232,34 @@ pub unsafe fn with_errp T>(f: F) -> R } } =20 +/// Extension trait for `std::result::Result`, providing extra +/// methods when the error type can be converted into a QEMU +/// Error. +pub trait ResultExt { + /// The success type `T` in `Result`. + type OkType; + + /// Report a fatal error and exit QEMU, or return the success value. + /// Note that, unlike [`unwrap()`](std::result::Result::unwrap), this + /// is not an abort and can be used for user errors. + fn unwrap_fatal(self) -> Self::OkType; +} + +impl ResultExt for std::result::Result +where + Error: From, +{ + type OkType =3D T; + + fn unwrap_fatal(self) -> T { + // SAFETY: errp is valid + self.map_err(|err| unsafe { + Error::from(err).propagate(addr_of_mut!(bindings::error_fatal)) + }) + .unwrap() + } +} + impl FreeForeign for Error { type Foreign =3D bindings::Error; =20 diff --git a/rust/util/src/lib.rs b/rust/util/src/lib.rs index 16c89b95174..d14aa14ca77 100644 --- a/rust/util/src/lib.rs +++ b/rust/util/src/lib.rs @@ -6,4 +6,4 @@ pub mod module; pub mod timer; =20 -pub use error::{Error, Result}; +pub use error::{Error, Result, ResultExt}; --=20 2.51.1