From patchwork Fri Dec 2 16:14:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Miguel Ojeda X-Patchwork-Id: 28971 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp947950wrr; Fri, 2 Dec 2022 08:18:53 -0800 (PST) X-Google-Smtp-Source: AA0mqf71iKrRPfOJSZiGUuimyKjYKkPiA/uE1gIxZWHok7SHNDtWmGl4JeZMquounrfqXnlDPzrH X-Received: by 2002:aa7:c9d0:0:b0:458:ed79:ed5 with SMTP id i16-20020aa7c9d0000000b00458ed790ed5mr49233171edt.374.1669997933372; Fri, 02 Dec 2022 08:18:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669997933; cv=none; d=google.com; s=arc-20160816; b=gnZGQ+uu997dv2NLExioB1rGc0fE8kR9K1GunzL/6oM/t7RUTKjIxbeIxqHEe/fHG5 HfgY2d9BdbLN6uMXp3fbdzOy7tAn/Lmc6j/wXHpN2XnAwJtd9RSCr/skHrfFAlljrSDH x+DR22YctktZ5OJSWKAZN8u0oiHltcK7xwPIIsQ9khkjlpiFIL8Xl10kLbVEMYx5Mvo5 5uYfDRiVWV1RkXvAoqAfPn+qzLnfquYQvhqCES+V9A4AuRWuOetWjXuQmV2HoKRfLnJs 9D6KAiM7IPRMiJKGBV+gagNotYYoWEjoARWj9LyOn06a975zt8wq5nSYpVd4xPc0l2iw XsUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=IqCDQzIn8PmU18Zo/aENvJsgJezqjD8PzkMlbpxej+E=; b=lSUlqywJgYXhVkw2oeM18jyas3QDcNNveiQQKqDBKG9thZHMyLZK7CUKvvdEjgfVti 1Jz3RIrsry2xqjynqyCg9Mz+YsgVUD8t3MzD1SasI6uVp+GtVVTuqvmNSbXNWsXiQdGL zKGRwEJGefx29mBr5wJbiWscwPoFDwX+PuUKzl4EIYbgDLRtPYxUNhkRdjVxbIXTITdZ Htefr/h+NF7coal/S0UHtV7DgT+Xu7ZNL8oqQVlxSslB4IlEuB4X1E0Ylg0UpPcVe95G /GCND3gGi8/NXIDWF//+IWaNmmIS8q5N09sTOGCcBhTT7rO+YxFJg0mXvZbluQj6x4my EiKA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="gFYHA5/t"; 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=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id nb30-20020a1709071c9e00b007acf3aed468si6842766ejc.786.2022.12.02.08.18.26; Fri, 02 Dec 2022 08:18:53 -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=@kernel.org header.s=k20201202 header.b="gFYHA5/t"; 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=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233850AbiLBQRS (ORCPT + 99 others); Fri, 2 Dec 2022 11:17:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53212 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233883AbiLBQQq (ORCPT ); Fri, 2 Dec 2022 11:16:46 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2655BAD9AC; Fri, 2 Dec 2022 08:16:18 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id AA01862321; Fri, 2 Dec 2022 16:16:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D479AC4314F; Fri, 2 Dec 2022 16:16:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1669997777; bh=lSrHt+F2Ze+/0shcXyGqT2iYHkhHUzJS18BpgwZFKfQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gFYHA5/tQJfrLY2tIEHdQ9SHhxkxhRakBLeDbRT0zxpv7dx9kQLQtuJazH6m6aVXf gnKkepKJPuKvfcuB+2X2jvp5nyDj+F6CRXRHzsc9xxdl5fD+uqVQACAuL+HBDYLfhA cZws+wpA/mtCbx2+K8HrvbpURAtnDTV7VEDKZmDKZ+GlnUV1NunRfGyBdTCeVwecce 8S5JEe5HR6yPWnaeesWeC+sKAqzLPdF6sjP5TIWLeSBKu/ynoy1Pzr3fN4gkdD3U9B c8n9On8iuaxdeTN4ShAFSbhU3ezYZ6NvicvI+dCMmS9AWRHvnTW38tF1CZJ1SOoHLZ /KyNk796JJ6PQ== From: ojeda@kernel.org To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Morgan Bartlett Subject: [PATCH v2 17/28] rust: str: implement several traits for `CStr` Date: Fri, 2 Dec 2022 17:14:48 +0100 Message-Id: <20221202161502.385525-18-ojeda@kernel.org> In-Reply-To: <20221202161502.385525-1-ojeda@kernel.org> References: <20221202161502.385525-1-ojeda@kernel.org> MIME-Version: 1.0 X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, 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 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751119752981624946?= X-GMAIL-MSGID: =?utf-8?q?1751119752981624946?= From: Gary Guo Implement `Debug`, `Display`, `Deref` (into `BStr`), `AsRef` and a set of `Index<...>` traits. This makes it `CStr` more convenient to use (and closer to `str`). Co-developed-by: Alex Gaynor Signed-off-by: Alex Gaynor Co-developed-by: Morgan Bartlett Signed-off-by: Morgan Bartlett Signed-off-by: Gary Guo [Reworded, adapted for upstream and applied latest changes] Signed-off-by: Miguel Ojeda --- rust/kernel/str.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index d66565f92f71..11d297c1a61c 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,7 +2,8 @@ //! String representations. -use core::fmt; +use core::fmt::{self, Write}; +use core::ops::{self, Deref, Index}; use crate::{ bindings, @@ -199,6 +200,127 @@ impl CStr { } } +impl fmt::Display for CStr { + /// Formats printable ASCII characters, escaping the rest. + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::str::CStr; + /// # use kernel::str::CString; + /// let penguin = c_str!("🐧"); + /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); + /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); + /// + /// let ascii = c_str!("so \"cool\""); + /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); + /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for &c in self.as_bytes() { + if (0x20..0x7f).contains(&c) { + // Printable character. + f.write_char(c as char)?; + } else { + write!(f, "\\x{:02x}", c)?; + } + } + Ok(()) + } +} + +impl fmt::Debug for CStr { + /// Formats printable ASCII characters with a double quote on either end, escaping the rest. + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::str::CStr; + /// # use kernel::str::CString; + /// let penguin = c_str!("🐧"); + /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); + /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); + /// + /// // Embedded double quotes are escaped. + /// let ascii = c_str!("so \"cool\""); + /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); + /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("\"")?; + for &c in self.as_bytes() { + match c { + // Printable characters. + b'\"' => f.write_str("\\\"")?, + 0x20..=0x7e => f.write_char(c as char)?, + _ => write!(f, "\\x{:02x}", c)?, + } + } + f.write_str("\"") + } +} + +impl AsRef for CStr { + #[inline] + fn as_ref(&self) -> &BStr { + self.as_bytes() + } +} + +impl Deref for CStr { + type Target = BStr; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_bytes() + } +} + +impl Index> for CStr { + type Output = CStr; + + #[inline] + fn index(&self, index: ops::RangeFrom) -> &Self::Output { + // Delegate bounds checking to slice. + // Assign to _ to mute clippy's unnecessary operation warning. + let _ = &self.as_bytes()[index.start..]; + // SAFETY: We just checked the bounds. + unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } + } +} + +impl Index for CStr { + type Output = CStr; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &Self::Output { + self + } +} + +mod private { + use core::ops; + + // Marker trait for index types that can be forward to `BStr`. + pub trait CStrIndex {} + + impl CStrIndex for usize {} + impl CStrIndex for ops::Range {} + impl CStrIndex for ops::RangeInclusive {} + impl CStrIndex for ops::RangeToInclusive {} +} + +impl Index for CStr +where + Idx: private::CStrIndex, + BStr: Index, +{ + type Output = >::Output; + + #[inline] + fn index(&self, index: Idx) -> &Self::Output { + &self.as_bytes()[index] + } +} + /// Allows formatting of [`fmt::Arguments`] into a raw buffer. /// /// It does not fail if callers write past the end of the buffer so that they can calculate the