From patchwork Fri Feb 23 16:37:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 205513 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:a81b:b0:108:e6aa:91d0 with SMTP id bq27csp701105dyb; Fri, 23 Feb 2024 08:39:16 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCXSQl7HeiEgMFzUE1ZYmQ70iXsSD6x/Bca7XXjuu9OTJZ6+/foCsSwlVX9iTS9UUmkvXAFSWcBLtFT/YEXcwHC2TLc/uQ== X-Google-Smtp-Source: AGHT+IEUAW7ZE1gL1OOa2cnu4dsF4MKbSdgffh77HQuvTRDp34N49qpw01goRHiyBK0e5MY6tPVQ X-Received: by 2002:a17:902:f80d:b0:1dc:4d63:7a0d with SMTP id ix13-20020a170902f80d00b001dc4d637a0dmr288089plb.41.1708706356495; Fri, 23 Feb 2024 08:39:16 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1708706356; cv=pass; d=google.com; s=arc-20160816; b=ziN5FII5US0L6CAJl0Sd3fqow3JaVVvQZDKLhH2g7chVC6KcTGE9tCPT0zB7+EgAQB 8quWJscnTDTciNUBni+VIrTimK5IpISSr/svbk676bhYk6iwQUpto+YL2/26EZr4+Iwa M8tdo+r0ViQjhVqaEU1S72luU1CbM27Gi44i4O9PLPkn/WPqA41QO/Pl71qs0PoCYhku cwmvXN3CC5rsiaZmmhr17OzcHUlXq8ZCXQIeSvMxamF/dpLfwrr32ocbm3rD6s2a943Q bdfcZLzfuveAMsVRbsDus8RYyBVFb8QlgkZP0JeiSRC3gAWZNEOr9ozQsjPMdV/VuShK 7HQQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=jJz4ul1e27rNZHJvoOXiYFCd5EfCVL6UYrKBkI3v9BM=; fh=p6m71hYepD4t2u9Cs5QfviQHjpftJ1qO5Kjs/72A90E=; b=sFZmnaakN2FlyoreUa0XFS/H4OfITQdeksaf9/QZObNllskHPfcnKx8VFRj+tj6lwa WOpKfCBBOhxDxax1T47IskKoZoJsuUX+mZrnA4XfHLJqQM3x5XzsI87rX5/4+ySCvdl8 lSWiJiyCvdexHpy++Bi/3a4RRzI/W9EOcz5mmQEn9xsCj5sWPvJZPRziwkUk9OIhnEuh YqCS8NPtZizRcBgtvI1c62pLuv0FQkB/0o9XQPxUK+QCFANmPUDvvorCEKAlWXCWfN6E umC7E7NJZCkUgbkja+jKNUqq+gU6i7FwpKodaGLL+vOqy+4vF9QPjKg0pkJ32RC6lAKr 5DBA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=X7SxLlJz; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-78739-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-78739-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id lq6-20020a170903144600b001dc04aa3863si8839344plb.473.2024.02.23.08.39.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Feb 2024 08:39:16 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-78739-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=X7SxLlJz; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-78739-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-78739-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 09774289CB0 for ; Fri, 23 Feb 2024 16:37:51 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 110F612A150; Fri, 23 Feb 2024 16:37:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="X7SxLlJz" Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 EA55882D74 for ; Fri, 23 Feb 2024 16:37:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708706256; cv=none; b=VKgQQVFXCuMu3RqGQsCE2+PueDTOXTbDLLAa4DkxJHPdPq4mpQL7mLqV7v0A5RU6O7A8dDpEy7JuZVRRFrfy8JGkM8vIbgEr7WSPCwCdRJTxvUl9RCKd5Mhytd8xuOCVX1N+/bZ0PruqFt8RpWteXIed6X9PvMdlGA6gKFqRUw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708706256; c=relaxed/simple; bh=6X2pjKgoujjJyMfMa5m9DAj7vZS/YUa15KPy8QFZibs=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=IaC4gSecDbtPKqXizIBSR3rdBuig4Ebbe0Fb+LpaN18ftZNCTgVmwpKZ5MxM9b0VtHi+ILDG/sIpYtmPUfVfW1Z4GqaM7cj2uOOIIpxsFz0T2X8oISM90IMynn9XTlpajVXFX3uBt9y8JrVdlDQQ8QRcgFeHGpFhxk9KwUeBp8w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=X7SxLlJz; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1708706253; 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; bh=jJz4ul1e27rNZHJvoOXiYFCd5EfCVL6UYrKBkI3v9BM=; b=X7SxLlJzGUD/+SSQWOEs4MLnWeU77H8E5MFlKSDi+mbD1NvvSC+otK8foiYgLzShz6TspK HpQwULA6scnepzViSUtNZzOmgzpUGoCBVSfa7U3Qt46goRW/C6ptiOvGOK4GFBpj84uyFr 2X11FGF4nEVK/OKCphIki353vdMjxVE= Received: from mail-lf1-f70.google.com (mail-lf1-f70.google.com [209.85.167.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-546-_u52cqdbN7yATReSICW_qw-1; Fri, 23 Feb 2024 11:37:32 -0500 X-MC-Unique: _u52cqdbN7yATReSICW_qw-1 Received: by mail-lf1-f70.google.com with SMTP id 2adb3069b0e04-512e13a6a70so911979e87.1 for ; Fri, 23 Feb 2024 08:37:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708706251; x=1709311051; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=jJz4ul1e27rNZHJvoOXiYFCd5EfCVL6UYrKBkI3v9BM=; b=R/byqLPoJ+P/e+8sm6dogKtYmQ7+mfHdrbgVht/I/DcBkE2qg/6ynoLv/H13X3jM/T ATtM2gt1Uc6M8p2QWXs3QdXZClXhmOwcLaUhqRgO6A3+wQkErXlYHbSujpPivpyGBSlS 7dMGy4UxErKT9v212esry5vi+L69saNkP9IErihihB5+jFI31BPOAMNBCY8vJm3jgZed TOBykDAqX2zlZmobMA5lB1rf7DBWMIF0jiejbDDmT51zmJt/j+AK4jjB9rUYDRkYQB5f 8hXrKdNFvaZKqzpt2ligumiq7fed8zUUbv+1Ai8kfewCv6yck1mIPVpxBv8pCFjJm2GU Sy9A== X-Forwarded-Encrypted: i=1; AJvYcCXsQcesGoeD+j7BUE+XME1zDA0FcbmYqKANn4UwfDUEOXm6rq0qs9GNBR5cMchwlaDcCk9/Qe3ndU6fX4KAtmpldzToDAjuge0SapYl X-Gm-Message-State: AOJu0YzOtzhEzbZETF7qpDHeQw4c2V4Y2+LNGRseggrGfw/qTnCBpqwK oNteVcYSIFYRIkJbf6fwQS8ke2s3UJrTqZ2U/jW6a69cRl9j2rXGXMGb8OmnzRTywZy/NlvcTYG SuW4/u0C1QGt2mqvkTar9DyeHGPpmEMnqIj7cxRN90K8uheHkJ+hJD5xaAdBJVQ== X-Received: by 2002:a19:7404:0:b0:512:d6b4:9622 with SMTP id v4-20020a197404000000b00512d6b49622mr133283lfe.69.1708706251108; Fri, 23 Feb 2024 08:37:31 -0800 (PST) X-Received: by 2002:a19:7404:0:b0:512:d6b4:9622 with SMTP id v4-20020a197404000000b00512d6b49622mr133270lfe.69.1708706250687; Fri, 23 Feb 2024 08:37:30 -0800 (PST) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id ev24-20020a056402541800b0056163b46393sm6542407edb.64.2024.02.23.08.37.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Feb 2024 08:37:30 -0800 (PST) From: Danilo Krummrich To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v5] rust: str: add {make,to}_{upper,lower}case() to CString Date: Fri, 23 Feb 2024 17:37:09 +0100 Message-ID: <20240223163726.12397-1-dakr@redhat.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1791708476368831545 X-GMAIL-MSGID: 1791708476368831545 Add functions to convert a CString to upper- / lowercase, either in-place or by creating a copy of the original CString. Naming followes the one from the Rust stdlib, where functions starting with 'to' create a copy and functions starting with 'make' perform an in-place conversion. This is required by the Nova project (GSP only Rust successor of Nouveau) to convert stringified enum values (representing different GPU chipsets) to strings in order to generate the corresponding firmware paths. See also [1]. [1] https://rust-for-linux.zulipchat.com/#narrow/stream/288089-General/topic/String.20manipulation.20in.20kernel.20Rust Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- Changes in V5: - remove unneeded return statements - use Vec::as_mut_slice() instead of a dereference Changes in V4: - move to_ascii_{lower,upper}case() to CStr - add a few comments suggested by Alice Changes in V3: - add an `impl DerefMut for CString`, such that these functions can be defined for `CStr` as `&mut self` and still be called on a `CString` Changes in V2: - expand commit message mentioning the use case - expand function doc comments to match the ones from Rust's stdlib - rename to_* to make_* and add the actual to_* implementations --- rust/kernel/str.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) base-commit: 39133352cbed6626956d38ed72012f49b0421e7b diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 7d848b83add4..c1c8ccc80c52 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -5,7 +5,7 @@ use alloc::alloc::AllocError; use alloc::vec::Vec; use core::fmt::{self, Write}; -use core::ops::{self, Deref, Index}; +use core::ops::{self, Deref, DerefMut, Index}; use crate::{ bindings, @@ -143,6 +143,19 @@ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError unsafe { core::mem::transmute(bytes) } } + /// Creates a mutable [`CStr`] from a `[u8]` without performing any + /// additional checks. + /// + /// # Safety + /// + /// `bytes` *must* end with a `NUL` byte, and should only have a single + /// `NUL` byte (or the string will be truncated). + #[inline] + pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { + // SAFETY: Properties of `bytes` guaranteed by the safety precondition. + unsafe { &mut *(bytes as *mut [u8] as *mut CStr) } + } + /// Returns a C pointer to the string. #[inline] pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { @@ -206,6 +219,70 @@ pub unsafe fn as_str_unchecked(&self) -> &str { pub fn to_cstring(&self) -> Result { CString::try_from(self) } + + /// Converts this [`CStr`] to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase()`]. + /// + /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase + pub fn make_ascii_lowercase(&mut self) { + // INVARIANT: This doesn't introduce or remove NUL bytes in the C + // string. + self.0.make_ascii_lowercase(); + } + + /// Converts this [`CStr`] to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase()`]. + /// + /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase + pub fn make_ascii_uppercase(&mut self) { + // INVARIANT: This doesn't introduce or remove NUL bytes in the C + // string. + self.0.make_ascii_uppercase(); + } + + /// Returns a copy of this [`CString`] where each character is mapped to its + /// ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// [`make_ascii_lowercase`]: str::make_ascii_lowercase + pub fn to_ascii_lowercase(&self) -> Result { + let mut s = self.to_cstring()?; + + s.make_ascii_lowercase(); + + Ok(s) + } + + /// Returns a copy of this [`CString`] where each character is mapped to its + /// ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// [`make_ascii_uppercase`]: str::make_ascii_uppercase + pub fn to_ascii_uppercase(&self) -> Result { + let mut s = self.to_cstring()?; + + s.make_ascii_uppercase(); + + Ok(s) + } } impl fmt::Display for CStr { @@ -593,6 +670,14 @@ fn deref(&self) -> &Self::Target { } } +impl DerefMut for CString { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: A `CString` is always NUL-terminated and contains no other + // NUL bytes. + unsafe { CStr::from_bytes_with_nul_unchecked_mut(self.buf.as_mut_slice()) } + } +} + impl<'a> TryFrom<&'a CStr> for CString { type Error = AllocError;