From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from CH1PR05CU001.outbound.protection.outlook.com (mail-northcentralusazon11010042.outbound.protection.outlook.com [52.101.193.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B0EC5352026; Fri, 16 Oct 2026 01:54:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.193.42 ARC-Seal:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792115659; cv=fail; b=RWkhXtKaHBpm0/epBicDZ/z5oNS7rtE37MtO/Hxc8mEexIUAAq70h/LSCcB+uOgDphKNf/k/Nj4Y+zJwyEUOOnJ7TFHC0MXsHjLCPGMIrXBN6cd24F/YsGFs+zCEryowzsmqyus0yhL2vN8n/AQy/cDvE7vS+jKxB9COtJ/vZqE= ARC-Message-Signature:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792115659; c=relaxed/simple; bh=4be1H6/onnsFzNnsFEb0Ebi03to6lh9K3bxuqkX3orQ=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=AAkhinRYjS8Laot8gN6FsuB8G+ByHQSbH2bQ21IU/aFIY1y7ubWlLLdkCC+69+ydYbMODFzBaOsouNPX0bh5DHHAXsCjfJYy5sssvZrd3ahDS0KNHh8vBqFVbmLW1YHXtVhlko5kBdYAdjO7HL0gEPNicwOMBRjYdyXeXnk3X/o= ARC-Authentication-Results:i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=a9iGRK6+; arc=fail smtp.client-ip=52.101.193.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="a9iGRK6+" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=mlXCv7areOkp4I3im8TxUa2ucpjvw3bxpb4jqAxcWvGmiKvA8722eIqIkEZYwnuj/cTpZZXE3/UU+cpqCeFB/k5kSDHkpGKus1HTeA3zx+YWJrYNN/w1WQxSzvFgxbP1pO7VaoGIWOjDou7PdOdZR3J5OAoWU9xJ68ebZeN8H/A/1k/cwRKWU5l2EFJnm/Ki23DjBt8LkIxHRhsg1RHXUCy+YTV0WHVwQEwkKp1+tVUG1bOBHhq2GnLuLZMZG0ue8RfsiPTAbQIFLyTWTt+pWhNNDKiU9GCkFUGY1OfcD6xGBsK9VPAzNU+jrk1C7gH0Zw30ZjPu8djkWm+IgvDmYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=7le30eyTxPCMHKUv1rtjFDk1i4D2xAPMejGCyo/JCKU=; b=ONCOxk1ISdtC+Xnz5z5/q4lJQagtFUt9Sw5fcCEI7tvEW6v5bug7IrovhmqQ1Nfgq+nF2WosxahjK3MaMyJbISg9/eD4oqmh0/QPAA93LlHyb1JptSe8ra0isQAFagdoRMeEfGrATuLHZHrNFGAe6MbBuLEELoTEGiCXej7yezHkZhRfbF4nyuyG0qCQigBiS9aZ8pwrb6EBoezDZUl0aM34b2Sw52pzkiuK1emrCVlNIx4dGfnR0L7+jkpzhDvvUIviITnZpB783jPNZVf4nbgXmD6Itu5t6B+NGLljM3mEsciqcWAkc55nprDxhQs8cx5fHA04aoBPtw1GAN/MMw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=7le30eyTxPCMHKUv1rtjFDk1i4D2xAPMejGCyo/JCKU=; b=a9iGRK6+3P7lJYdmAlD3ql2WmINf5WrbZX4bcvVBHtEU1hz2X55L50EYeLIbgSLCc5KARmy8o3iuXz8otFZZLBLA0AL5xBCdoF/eRCfezItYQ8so2I40VI+VabYd2r13Xsr2TyrUwXOGGbYrlo8zNDNcD5hPWKnzMJntkYyr0KaCi/S8vpPIpam1U3YJ5C4ipvJPfYRiO3c8CktVwtYBB1yTO9oINj5ccdmNXHHAp8jdem3UCl4xOSCArvh8xuSNQ3Zt5Vlz+IFHI01qFXSQcJ2tQb4eTVdP6L2fjf8PRv0hZtpYw/357B2Gjt/dzENg6J4w2C0CQ0jwFJ5HC+sTNw== Authentication-Results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from DS0PR12MB6413.namprd12.prod.outlook.com (2603:10b6:8:ce::10) by SA1PR12MB999230.namprd12.prod.outlook.com (2603:10b6:806:4de::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.522.14; Fri, 16 Oct 2026 01:54:14 +0000 Received: from DS0PR12MB6413.namprd12.prod.outlook.com ([fe80::e82a:6673:4142:37fa]) by DS0PR12MB6413.namprd12.prod.outlook.com ([fe80::e82a:6673:4142:37fa%5]) with mapi id 15.21.0496.021; Fri, 16 Oct 2026 01:54:14 +0000 From: Eliot Courtney Date: Fri, 16 Oct 2026 10:53:38 +0900 Subject: [PATCH v4 2/7] rust: alloc: add ArrayVec Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20261016-b4-nvkv-v4-2-e8b92b91aa5b@nvidia.com> References: <20261016-b4-nvkv-v4-0-e8b92b91aa5b@nvidia.com> In-Reply-To: <20261016-b4-nvkv-v4-0-e8b92b91aa5b@nvidia.com> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , David Airlie , Simona Vetter Cc: John Hubbard , Alistair Popple , Timur Tabi , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, Eliot Courtney X-Mailer: b4 0.15.2 X-ClientProxiedBy: TYCP286CA0143.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:31b::19) To DS0PR12MB6413.namprd12.prod.outlook.com (2603:10b6:8:ce::10) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DS0PR12MB6413:EE_|SA1PR12MB999230:EE_ X-MS-Office365-Filtering-Correlation-Id: 7f74e4cf-2490-4cc8-c45f-08df2b286120 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|7416014|23010399003|10070799003|366016|376014|6133799003|18002099003|10067099003|22082099003|921020|261009223027099003|11063799006|56012099006; X-Microsoft-Antispam-Message-Info: /M7aEbKYPmMT70ADCKNcOUM2DbMBAZJ4XhbQV4ywXI8820r/GWRIUmopJh+K4AUMYtL8r3P1Q+dmBRa+XVzeCbsfQfbjnTnfxq+KtnfAyHK2nnz31NLHmKDxFlAi0BRTfK88ZGcPUYQ83iql/NE27WZnGoL+BOa32n2MxYIK1IMs5EAjv5ydCSB/huRu2YGOfw2W1gqyAOvAw6g5VcaAGqwJtukMZ3cWW01YWtrFFsJTwKLXD2cbRxoauHmDOtl+mubsFluRBztQB4ZU8SxNSw/JYTDWv0Ciwl+3F0Wm6xwygMmx+MNvOI/lKFxOH1aSFGOlsPpEeDkbkca3Czkx7JXy1dfyD6Skg2+7H2hmBb5djiDxDhSCBeRmNc9lnyYLfpo/uGz2ue8G582NsCcmO9sEFtoLHT5FY2tkmNUGAsr8PKtjl3LcKsIVZtB6NoRvE2kZuJtgy6Za4WaYizITljksZyE8O3WQO6F+xDXJS0S7+ENhgcmlv9H2LcH3F812/SCaUiR5AceQnpa6YfDGhIzr8TfRdrsfTWWan2JecxoLGRjMEr4ybvXBQJX202xRuLWAsVLmXHaZtLdxALd3gpzi3nhUs13Bx3K6UdhGuV7JEuTsNYOFrD4Zt48GWnlNVyT2HIVQBi71b3JxNl7ZeC5HK7iK/92Ug+sV23C0HcdZzKg5C2V6dmlOwNFmydWS1oWWziUt5gZ3dxVVZQoszA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR12MB6413.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(7416014)(23010399003)(10070799003)(366016)(376014)(6133799003)(18002099003)(10067099003)(22082099003)(921020)(261009223027099003)(11063799006)(56012099006);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?S29QbS9pZjhqZGNYbWpDOU5NdnI4cW03aXlpRGRUU1ZLR3RVOW02c0JRSCtl?= =?utf-8?B?anpBdGlwS2xIVTVsVGVNMWE4b0pRL0pmcGlwKzBNRmE1ZjE2QVZZZEp1M1Jt?= =?utf-8?B?ZVEwUjFIMXZMK0R1M3NxUm9SUEtuTVRRREo5Sk5aU3ROSUVTSjJON2NVclNq?= =?utf-8?B?MlJhWFBnVlBmMmQrU0NjMmdhRGdHKzBaUjh5Z0lLNlJxcWdXdnk0ZXVFTkxn?= =?utf-8?B?azVsSUJ6NFhuNS9WejhFV1dJZXpUMkI5MkVvWkJpczluQW9oY2YrTVp0dDB1?= =?utf-8?B?TkxXa09kb2daY3BjVElaMHFEOVpvTndtZFhWWGMzaUFmOWUya2I2VU1mQzN1?= =?utf-8?B?cEVTVmE1b0ZuVS81UStwd2RRLzJZNW5Fc0lOOTdCeWNYbXNCWXRMYUh3aUdn?= =?utf-8?B?cElrVVBNWXgxNG4yaUJINVVudXVBMUJzT3JNclVFakNjVWwvQ1BjS3BsV3h5?= =?utf-8?B?WTlNUnB4QmJuZTdDRGJYM3BEaVg0aHNJVzBVRkZTd09Tczk2N011V2YzV2I4?= =?utf-8?B?STlsdmg2SW95UkUzUlgzUGJjbzkzTFo3TkJKN0NBbkFDWTh4akYzcjdSMEVP?= =?utf-8?B?bksrZHNlellmQVB6NWJ4RlAxZWhGSHJ0NkRmL0pVMkpScGxtV2RzaXhmN2xY?= =?utf-8?B?QWVqc0tKaDBiQ0xtQVZBYWtBaC9TN2kxNUt5cU1ISGJVUnRIclM0SXBWVEg1?= =?utf-8?B?d2dCd20vMXBRSFF3eWJucTNnQUhZc1o0TXRIcjFRSDF4b2RqQXNRZkg5Y3BB?= =?utf-8?B?aWlNTkEra1diQTQwS1RXTVNwQ0xWZndaRkovWWx6OTgwMGhNWUhDZ3ZleEh5?= =?utf-8?B?bHdWYXV6RmhFZ0JncnczSkcyMFBSQmVwZjV0K1R6aDN2ZDM5cEZ6Z0VVMVNL?= =?utf-8?B?cDlTQXBWN3NrVEhmZklmMW42WmNnVXpNa2JLT25IclhvRnpGRzBnU0s2S3lI?= =?utf-8?B?U0IrbFBtNHFpeFRwd3pmNEwzZlNyTmhmRWU2SC9JdzliV3RjaWt4R1krcUhr?= =?utf-8?B?ZVpWNXpDS3pmd0tEL3lrN3VtZHIxbmpmUEMwdUVrcHBFWnY3cFFIeFUwLzFW?= =?utf-8?B?dDRpVDVrcE1UMmxkRDNBZ3RGV2ZTblYvb2NzNzVVMTc1YldiUlJVS1ZGZWNl?= =?utf-8?B?VWFlcHAybmtOcjAzNnQxdDQvNHJ0Sk0rVEIrSzlHU3RudURWeUNOdHVjeUl5?= =?utf-8?B?VjFJQVNCVTBCUVJmV1ROZVlRMXozSEQvaDR2cVpXZzBvVWZ3RXdpa0sxMXRx?= =?utf-8?B?RXJ2M0ZkR3VZOWc3cVU0dkFsb21zNS93ZVdJaFZkOFIwT1ZMSmZ1N2FEa3VE?= =?utf-8?B?ZUFKdTdvc1VodlRZQVRoSFJzRXo4MTlVTjhrdlFPUUNFS0JkdWdCVlRyUzZ6?= =?utf-8?B?YkdYYVJHVCs5eTF5bWkwVnhabkxOWXBCbFA2b2JoVXM3eGcxMUwrWjJBcGhE?= =?utf-8?B?ek95akF5VGs1bWY3aXJFZS93M2dmU3pZWDdCWlVXUllha21US0tQUDZGa1JF?= =?utf-8?B?OC9vVDBhQlFuUy8vTFR2N2pUaWlpSmVEbG5YL2o4MG5INExMT0tMbERDSGNq?= =?utf-8?B?SXJXSzJ1NlB6N0JWTDUzbFI4aXVQOUpUWndYRWhSWGVueEwvWDl5eXcvbGdM?= =?utf-8?B?QzRibk1PTlFhajkzNFcvZUZEVnU0eEUvNkR2U1JMVUtwdS9CVFRQU3hMWVVy?= =?utf-8?B?YVBrbVlKb0xoY3A1ZElEOXIxdW9qT291MDVzeTdNTFU5OEQ2elB1SDdpemFp?= =?utf-8?B?Qk5QQ1pzQUU2c2xZdEl6MWhTTnlvd2VvZkZ3am9YaC94cDk0dzhJUGNiK2lC?= =?utf-8?B?R1dwK1JOMlo1SU9TK0tQRFZjd1o4TDFnRHNBMEJjYUNmamxaTk4ybTZuSWs0?= =?utf-8?B?ZitTYkNXM2lIa0tvSnRrL1dBK1BBcnR5WHFWR3hmV3FCTjF1TS8yS1FXa2hS?= =?utf-8?B?YWRxaUl5Y29BcTJSWWVDYkRLRWlLVFF0NWxsSGRaNjlLQ3JOTjl0RVBSMThT?= =?utf-8?B?RlkrbVlYOTk5NVR3K0gxL0pwQ3pQV2w5VGtGdEIvMzkxS3dyem4vWkx6UWo2?= =?utf-8?B?R2pQVmxYd0NVYW9KdTR2WDFIVVpLYVpNc0hBSzA1aWE3d29ONktqQ0RZbGxY?= =?utf-8?B?bmRDT25oaFhvb2J5Qm5BV3dCYkVZMmxKNjM0UGU0MVoxckhTZ2JuRFIxbGRp?= =?utf-8?B?SzNib0cwZWszZUIwWEpHekFieGp5V2xMUkNDQ3FnUTZQOVR0cXBHVjVxdjhY?= =?utf-8?B?UWJxWWNQbE8yOGJmbndlUUJzYkJNZEtSRmgrdE5icVcvVXZPM0V1aUc0OTR3?= =?utf-8?B?WTM0MnNqNmZCN21UdmlNKzg1MkVjZkhNUU85RTF3Tm4zUXFNN0oxT1ROTGNK?= =?utf-8?Q?hE0NHwMupS+9mM2IDBNpkdHPBwwf76xenUGLOv9Zi+PTe?= X-MS-Exchange-AntiSpam-MessageData-1: gwyBTJecexA2+Q== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7f74e4cf-2490-4cc8-c45f-08df2b286120 X-MS-Exchange-CrossTenant-AuthSource: DS0PR12MB6413.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Oct 2026 01:54:13.9345 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: i0s/7GU6iPpcQX9YmSxX2R3HVo9bS7e50XeN8iRh9UbS3oNuDs0Zsxhz8sLYgpsOtFXHW/qfdyhJe91sJshCNw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA1PR12MB999230 Add a fixed capacity vector backed by [MaybeUninit; N]. The ArrayVec is also initializable with a closure, returning an Init instance, to avoid constructing it on the stack. ArrayVec is useful for small but varying size arrays stored on the stack, to avoid a heap allocation, or, for larger varying size arrays initialized into caller provided memory but not wanting to provide an allocator. Signed-off-by: Eliot Courtney --- rust/kernel/alloc.rs | 3 + rust/kernel/alloc/arrayvec.rs | 338 +++++++++++++++++++++++++++++++++++++++ rust/kernel/alloc/kvec.rs | 1 + rust/kernel/alloc/kvec/errors.rs | 2 +- 4 files changed, 343 insertions(+), 1 deletion(-) diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 21067bde6860..510e2c7f9f72 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -3,10 +3,13 @@ //! Implementation of the kernel's memory allocation infrastructure. pub mod allocator; +pub mod arrayvec; pub mod kbox; pub mod kvec; pub mod layout; +pub use self::arrayvec::ArrayVec; + pub use self::kbox::Box; pub use self::kbox::KBox; pub use self::kbox::KVBox; diff --git a/rust/kernel/alloc/arrayvec.rs b/rust/kernel/alloc/arrayvec.rs new file mode 100644 index 000000000000..8793adf4d27b --- /dev/null +++ b/rust/kernel/alloc/arrayvec.rs @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Implementation of [`ArrayVec`]. + +use crate::{ + alloc::kvec::{ + impl_slice_eq, + PushError, // + }, + const_assert, + error::{ + code::EINVAL, + Error, + Result, // + }, + fmt, // +}; + +use core::{ + borrow::{ + Borrow, + BorrowMut, // + }, + mem::MaybeUninit, + ops::{ + Deref, + DerefMut, // + }, + ptr, + slice, // +}; + +use pin_init::{ + init_from_closure, + Init, + Zeroable, // +}; + +/// A fixed capacity vector that holds at most `N` elements. +/// +/// # Invariants +/// +/// - `len` is at most `N`. +/// - The first `len` elements of `data` are initialized. +/// +/// # Examples +/// +/// ``` +/// use kernel::alloc::ArrayVec; +/// +/// let mut v = ArrayVec::::new(); +/// v.extend_from_slice(b"abc")?; +/// assert_eq!(*v, *b"abc"); +/// +/// assert!(v.extend_from_slice(b"ab").is_err()); +/// +/// v.push(4u8)?; +/// assert_eq!(*v, *b"abc\x04"); +/// assert!(v.push(5u8).is_err()); +/// +/// v.clear(); +/// assert!(v.is_empty()); +/// # Ok::<(), Error>(()) +/// ``` +#[derive(Zeroable)] +pub struct ArrayVec { + data: [MaybeUninit; N], + len: usize, +} + +/// The maximum size in bytes of an [`ArrayVec`] returned by value from [`ArrayVec::new`]. +const MAX_STACK_SIZE: usize = 512; + +impl ArrayVec { + /// Creates an empty [`ArrayVec`]. + #[inline] + pub const fn new() -> Self { + const_assert!( + size_of::() <= MAX_STACK_SIZE, + "use `init_with` instead of constructing a large ArrayVec on the stack" + ); + + // INVARIANT: An empty ArrayVec trivially has all its elements initialized. + Self { + data: [const { MaybeUninit::uninit() }; N], + len: 0, + } + } + + /// Creates an initializer for an [`ArrayVec`] populated by `f`. + /// + /// `f` gets an empty [`ArrayVec`] and can fill it in place. + /// + /// # Examples + /// + /// ``` + /// use kernel::alloc::ArrayVec; + /// + /// let v = KBox::init( + /// ArrayVec::::init_with(|v| v.extend_from_slice(b"abc")), + /// GFP_KERNEL, + /// )?; + /// assert_eq!(**v, *b"abc"); + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + pub fn init_with(f: impl FnOnce(&mut Self) -> Result<(), E>) -> impl Init { + let init_empty = |slot: *mut Self| { + // SAFETY: By the initializer contract `slot` is valid for writes. Once `len` is zero + // the slot holds a valid empty ArrayVec, since `data` requires no initialization. + // INVARIANT: An empty ArrayVec trivially has all its elements initialized. + unsafe { (&raw mut (*slot).len).write(0) }; + Ok(()) + }; + + // SAFETY: `init_empty` fully initializes the slot and never fails. + unsafe { init_from_closure(init_empty) }.chain(f) + } + + /// Appends an element to the back of the [`ArrayVec`]. + /// + /// Fails when the [`ArrayVec`] is full, handing the element back in [`PushError`]. + #[inline] + pub fn push(&mut self, v: T) -> Result<(), PushError> { + self.try_push_init(v) + .map_err(|TryPushInitError::Full(v)| PushError(v)) + } + + /// Appends an element to the back of the [`ArrayVec`] by initializing it in place. + /// + /// Fails when the [`ArrayVec`] is full, handing the initializer back in [`PushError`]. + #[inline] + pub fn push_init>(&mut self, init: I) -> Result<(), PushError> { + self.try_push_init(init) + .map_err(|TryPushInitError::Full(init)| PushError(init)) + } + + /// Appends an element to the back of the [`ArrayVec`] by initializing it in place. + /// + /// Unlike [`ArrayVec::push_init`], the initializer may be fallible. If the [`ArrayVec`] is + /// full, the original initializer `init` is handed back in [`TryPushInitError::Full`]. If the + /// initializer itself fails, its error is returned in [`TryPushInitError::InitError`]. + pub fn try_push_init(&mut self, init: I) -> Result<(), TryPushInitError> + where + I: Init, + { + let Some(slot) = self.spare_capacity_mut().first_mut() else { + return Err(TryPushInitError::Full(init)); + }; + + // SAFETY: + // - `slot.as_mut_ptr()` points to a spare slot, which is valid, uninitialized memory. + // - If `raw_try_init` fails, this returns without increasing `len` or touching `slot`. + // - `init` implements `Init`, which removes the pinning requirement. + unsafe { pin_init::raw_try_init(slot.as_mut_ptr(), init) } + .map_err(TryPushInitError::InitError)?; + + // INVARIANT: The element at index `len` was just initialized, and the new `len` does not + // exceed `N` because a spare slot existed. + self.len += 1; + + Ok(()) + } + + /// Appends a clone of each element in `slice` to the back of the [`ArrayVec`]. + /// + /// Fails with [`EINVAL`] if `slice` is longer than the remaining capacity. + pub fn extend_from_slice(&mut self, slice: &[T]) -> Result + where + T: Clone, + { + let Some(dst) = self.spare_capacity_mut().get_mut(..slice.len()) else { + return Err(EINVAL); + }; + + for (d, s) in dst.iter_mut().zip(slice) { + d.write(s.clone()); + } + // INVARIANT: The next `slice.len()` elements after `len` were just initialized, and the + // new `len` does not exceed `N` because the spare capacity was enough. + self.len += slice.len(); + + Ok(()) + } + + /// Removes all elements. + #[inline] + pub fn clear(&mut self) { + let elems: *mut [T] = self.as_mut_slice(); + // INVARIANT: An empty ArrayVec trivially has all its elements initialized. + self.len = 0; + // SAFETY: There are no references to the elements since we hold `&mut self`. The elements + // can't be dropped again because `len` is already 0. + unsafe { ptr::drop_in_place(elems) }; + } + + /// Returns the initialized elements as a slice. + #[inline] + pub fn as_slice(&self) -> &[T] { + let ptr = self.data.as_ptr().cast::(); + // SAFETY: `MaybeUninit` has the same layout as `T`, and by the type invariants the first + // `len` elements of `data` are initialized. + unsafe { slice::from_raw_parts(ptr, self.len) } + } + + /// Returns the initialized elements as a mutable slice. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + let ptr = self.data.as_mut_ptr().cast::(); + // SAFETY: `MaybeUninit` has the same layout as `T`, and by the type invariants the first + // `len` elements of `data` are initialized. + unsafe { slice::from_raw_parts_mut(ptr, self.len) } + } + + /// Returns a slice of `MaybeUninit` for the remaining spare capacity of the [`ArrayVec`]. + #[inline] + fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + // PANIC: `len` never exceeds `N` by the type invariants. + &mut self.data[self.len..] + } +} + +/// Error type for [`ArrayVec::try_push_init`]. +pub enum TryPushInitError { + /// The [`ArrayVec`] is full. Hand the initializer back. + Full(I), + /// The initializer failed. + InitError(E), +} + +impl fmt::Debug for TryPushInitError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TryPushInitError::Full(_) => write!(f, "Not enough capacity"), + TryPushInitError::InitError(_) => write!(f, "Initializer failed"), + } + } +} + +impl From> for Error +where + Error: From, +{ + #[inline] + fn from(e: TryPushInitError) -> Error { + match e { + TryPushInitError::Full(_) => EINVAL, + TryPushInitError::InitError(e) => Error::from(e), + } + } +} + +impl Default for ArrayVec { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Drop for ArrayVec { + #[inline] + fn drop(&mut self) { + // SAFETY: The slice holds initialized elements that are never accessed again after this + // point. + unsafe { ptr::drop_in_place(self.as_mut_slice()) }; + } +} + +impl Deref for ArrayVec { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl DerefMut for ArrayVec { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} + +impl Borrow<[T]> for ArrayVec { + #[inline] + fn borrow(&self) -> &[T] { + self.as_slice() + } +} + +impl BorrowMut<[T]> for ArrayVec { + #[inline] + fn borrow_mut(&mut self) -> &mut [T] { + self.as_mut_slice() + } +} + +impl Eq for ArrayVec {} + +impl_slice_eq! { + [const N: usize, const M: usize] ArrayVec, ArrayVec, + [const N: usize] ArrayVec, &[U], + [const N: usize] ArrayVec, &mut [U], + [const N: usize] &[T], ArrayVec, + [const N: usize] &mut [T], ArrayVec, + [const N: usize] ArrayVec, [U], + [const N: usize] [T], ArrayVec, + [const N: usize, const M: usize] ArrayVec, [U; M], + [const N: usize, const M: usize] ArrayVec, &[U; M], +} + +impl<'a, T, const N: usize> IntoIterator for &'a ArrayVec { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, const N: usize> IntoIterator for &'a mut ArrayVec { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl fmt::Debug for ArrayVec { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), f) + } +} diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index c8b312f64657..cd0c57a9ad90 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -1255,6 +1255,7 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } )* } } +pub(super) use impl_slice_eq; impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec, Vec, diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs index d24dfe22834a..f5c44fdc7016 100644 --- a/rust/kernel/alloc/kvec/errors.rs +++ b/rust/kernel/alloc/kvec/errors.rs @@ -7,7 +7,7 @@ prelude::*, // }; -/// Error type for [`Vec::push_within_capacity`]. +/// Error type for a push that fails because there is no spare capacity. pub struct PushError(pub T); impl fmt::Debug for PushError { -- 2.56.0