diff --git a/Cargo.lock b/Cargo.lock index 8cbce969433..ad27e139d22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2662,6 +2662,17 @@ dependencies = [ "tinystr-raw", ] +[[package]] +name = "tinystr-neo" +version = "0.3.1" +dependencies = [ + "bincode", + "displaydoc", + "postcard", + "serde", + "serde_json", +] + [[package]] name = "tinystr-raw" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index f7bc2e87204..48d531bbc07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ members = [ "experimental/list_formatter", "experimental/segmenter", "experimental/segmenter_lstm", + "experimental/tinystr_neo", "ffi/diplomat", "ffi/ecma402", "provider/blob", diff --git a/experimental/tinystr_neo/Cargo.toml b/experimental/tinystr_neo/Cargo.toml new file mode 100644 index 00000000000..d401b5a427e --- /dev/null +++ b/experimental/tinystr_neo/Cargo.toml @@ -0,0 +1,34 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "tinystr-neo" +version = "0.3.1" +description = "A small ASCII-only bounded length string representation." +authors = ["Manish Goregaokar "] +edition = "2021" +repository = "https://github.com/unicode-org/icu4x" +license-file = "LICENSE" +keywords = ["string", "str", "small", "tiny", "no_std"] +categories = ["data-structures"] +include = [ + "src/**/*", + "examples/**/*", + "benches/**/*", + "Cargo.toml", + "LICENSE", + "README.md" +] + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +displaydoc = { version = "0.2.3", default-features = false } +serde = { version = "1.0.123", optional = true, default-features = false, features = ["alloc"] } + +[dev-dependencies] +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +bincode = "1.3" +postcard = { version = "0.7", features = ["use-std"] } diff --git a/experimental/tinystr_neo/LICENSE b/experimental/tinystr_neo/LICENSE new file mode 100644 index 00000000000..5ab1f57507b --- /dev/null +++ b/experimental/tinystr_neo/LICENSE @@ -0,0 +1,331 @@ +Except as otherwise noted below, ICU4X is licensed under the Apache +License, Version 2.0 (included below) or the MIT license (included +below), at your option. Unless importing data or code in the manner +stated below, any contribution intentionally submitted for inclusion +in ICU4X by you, as defined in the Apache-2.0 license, shall be dual +licensed in the foregoing manner, without any additional terms or +conditions. + +As exceptions to the above: +* Portions of ICU4X that have been adapted from ICU4C and/or ICU4J are +under the Unicode license (included below) and/or the ICU license +(included below) as indicated by source code comments. +* Unicode data incorporated in ICU4X is under the Unicode license +(included below). +* Your contributions may import code from ICU4C and/or ICU4J and +Unicode data under these licenses. Indicate the license and the ICU4C +or ICU4J origin in source code comments. + +- - - - + +Apache License, version 2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +- - - - + +MIT License + +Copyright The ICU4X Authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +- - - - + +Unicode License + +COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later) + +Copyright © 1991-2020 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +- - - - + +ICU License - ICU 1.8.1 to ICU 57.1 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2016 International Business Machines Corporation and others +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + +- - - - diff --git a/experimental/tinystr_neo/README.md b/experimental/tinystr_neo/README.md new file mode 100644 index 00000000000..59106205269 --- /dev/null +++ b/experimental/tinystr_neo/README.md @@ -0,0 +1,7 @@ +# tinystr-neo [![crates.io](https://img.shields.io/crates/v/tinystr-neo)](https://crates.io/crates/tinystr-neo) + + + +## More Information + +For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/experimental/tinystr_neo/src/ascii.rs b/experimental/tinystr_neo/src/ascii.rs new file mode 100644 index 00000000000..28a2a78a6c6 --- /dev/null +++ b/experimental/tinystr_neo/src/ascii.rs @@ -0,0 +1,80 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::TinyStrError; +use core::ops::Deref; +use core::str::{self, FromStr}; + +#[repr(transparent)] +#[derive(PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Debug, Hash)] +pub struct TinyAsciiStr { + bytes: [u8; N], +} + +impl TinyAsciiStr { + pub const fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() > N { + return Err(TinyStrError::TooLarge { + max: N, + found: bytes.len(), + }); + } + + let mut out = [0; N]; + let mut i = 0; + while i < bytes.len() { + if bytes[i] == 0 { + return Err(TinyStrError::ContainsNull); + } else if bytes[i] >= 0x80 { + return Err(TinyStrError::NonAscii); + } + out[i] = bytes[i]; + + i += 1; + } + + Ok(Self { bytes: out }) + } + + pub const fn from_str(s: &str) -> Result { + Self::from_bytes(s.as_bytes()) + } + + pub fn len(&self) -> usize { + self.bytes.iter().position(|x| *x == 0).unwrap_or(N) + } + + pub fn is_empty(&self) -> bool { + self.bytes[0] == 0 + } + + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[0..self.len()] + } + + pub fn all_bytes(&self) -> &[u8; N] { + &self.bytes + } + + /// # Safety + /// Must be called with a bytes array made of valid ASCII bytes, with no null bytes + /// between ASCII characters + pub const unsafe fn from_bytes_unchecked(bytes: [u8; N]) -> Self { + Self { bytes } + } +} + +impl Deref for TinyAsciiStr { + type Target = str; + fn deref(&self) -> &str { + unsafe { str::from_utf8_unchecked(self.as_bytes()) } + } +} + +impl FromStr for TinyAsciiStr { + type Err = TinyStrError; + fn from_str(s: &str) -> Result { + Self::from_str(s) + } +} diff --git a/experimental/tinystr_neo/src/error.rs b/experimental/tinystr_neo/src/error.rs new file mode 100644 index 00000000000..fc735596816 --- /dev/null +++ b/experimental/tinystr_neo/src/error.rs @@ -0,0 +1,15 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use displaydoc::Display; + +#[derive(Display, Debug)] +pub enum TinyStrError { + #[displaydoc("found string of larger length {found} when constructing string of length {max}")] + TooLarge { max: usize, found: usize }, + #[displaydoc("tinystr types do not support strings with null bytes")] + ContainsNull, + #[displaydoc("attempted to construct TinyStrAuto from a non-ascii string")] + NonAscii, +} diff --git a/experimental/tinystr_neo/src/lib.rs b/experimental/tinystr_neo/src/lib.rs new file mode 100644 index 00000000000..92b991aefca --- /dev/null +++ b/experimental/tinystr_neo/src/lib.rs @@ -0,0 +1,25 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +#![cfg_attr(not(test), no_std)] + +mod macros; + +mod ascii; +mod error; + +#[cfg(feature = "serde")] +mod serde; + +#[cfg(feature = "serde")] +extern crate alloc; + +pub use ascii::TinyAsciiStr; +pub use error::TinyStrError; + +// /// Allows unit tests to use the macro +// #[cfg(test)] +// mod tinystr { +// pub use super::{TinyAsciiStr, TinyStrError}; +// } diff --git a/experimental/tinystr_neo/src/macros.rs b/experimental/tinystr_neo/src/macros.rs new file mode 100644 index 00000000000..5f7c2b67621 --- /dev/null +++ b/experimental/tinystr_neo/src/macros.rs @@ -0,0 +1,30 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +#[macro_export] +macro_rules! tinystr { + ($n:literal, $s:literal) => {{ + // Force it into a const context; otherwise it may get evaluated at runtime instead. + const TINYSTR_MACRO_CONST: $crate::TinyAsciiStr<$n> = { + match $crate::TinyAsciiStr::from_bytes($s.as_bytes()) { + Ok(s) => s, + // Cannot format the error since formatting isn't const yet + Err(_) => panic!(concat!("Failed to construct tinystr from ", $s)), + } + }; + TINYSTR_MACRO_CONST + }}; +} + +#[cfg(test)] +mod tests { + #[test] + fn test_macro_construction() { + let s1 = tinystr!(8, "foobar"); + assert_eq!(&*s1, "foobar"); + + let s1 = tinystr!(12, "foobarbaz"); + assert_eq!(&*s1, "foobarbaz"); + } +} diff --git a/experimental/tinystr_neo/src/serde.rs b/experimental/tinystr_neo/src/serde.rs new file mode 100644 index 00000000000..933491f1782 --- /dev/null +++ b/experimental/tinystr_neo/src/serde.rs @@ -0,0 +1,91 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::TinyAsciiStr; +use alloc::borrow::Cow; +use alloc::string::ToString; +use core::fmt; +use core::marker::PhantomData; +use core::ops::Deref; +use serde::de::{Error, SeqAccess, Visitor}; +use serde::ser::SerializeTuple; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +impl Serialize for TinyAsciiStr { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + self.deref().serialize(serializer) + } else { + let mut seq = serializer.serialize_tuple(N)?; + for byte in self.all_bytes() { + seq.serialize_element(byte)?; + } + seq.end() + } + } +} + +struct TinyAsciiStrVisitor { + marker: PhantomData>, +} + +impl TinyAsciiStrVisitor { + fn new() -> Self { + TinyAsciiStrVisitor { + marker: PhantomData, + } + } +} + +impl<'de, const N: usize> Visitor<'de> for TinyAsciiStrVisitor { + type Value = TinyAsciiStr; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a TinyAsciiStr<{}>", N) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut bytes = [0u8; N]; + let mut zeroes = false; + for out in &mut bytes.iter_mut().take(N) { + let byte = seq + .next_element()? + .ok_or_else(|| Error::invalid_length(N, &self))?; + if byte == 0 { + zeroes = true; + } else if zeroes { + return Err(Error::custom("TinyAsciiStr cannot contain null bytes")); + } + + if byte >= 0x80 { + return Err(Error::custom("TinyAsciiStr cannot contain non-ascii bytes")); + } + *out = byte; + } + + Ok(unsafe { TinyAsciiStr::from_bytes_unchecked(bytes) }) + } +} + +impl<'de, const N: usize> Deserialize<'de> for TinyAsciiStr { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + let x: Cow<'de, str> = Deserialize::deserialize(deserializer)?; + TinyAsciiStr::from_str(&x).map_err(|e| Error::custom(e.to_string())) + } else { + deserializer.deserialize_tuple(N, TinyAsciiStrVisitor::::new()) + } + } +} diff --git a/experimental/tinystr_neo/tests/serde.rs b/experimental/tinystr_neo/tests/serde.rs new file mode 100644 index 00000000000..f99a58619e3 --- /dev/null +++ b/experimental/tinystr_neo/tests/serde.rs @@ -0,0 +1,39 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use tinystr_neo::*; + +// Tests largely adapted from `tinystr` crate +// https://github.com/zbraniecki/tinystr/blob/4e4eab55dd6bded7f29a18b41452c506c461716c/tests/serde.rs + +macro_rules! test_roundtrip { + ($f:ident, $n:literal, $val:expr) => { + #[test] + fn $f() { + let tiny: TinyAsciiStr<$n> = $val.parse().unwrap(); + let json_string = serde_json::to_string(&tiny).unwrap(); + let expected_json = concat!("\"", $val, "\""); + assert_eq!(json_string, expected_json); + let recover: TinyAsciiStr<$n> = serde_json::from_str(&json_string).unwrap(); + assert_eq!(&*tiny, &*recover); + + let bin = bincode::serialize(&tiny).unwrap(); + assert_eq!(bin, &tiny.all_bytes()[..]); + let debin: TinyAsciiStr<$n> = bincode::deserialize(&bin).unwrap(); + assert_eq!(&*tiny, &*debin); + + let post = postcard::to_stdvec(&tiny).unwrap(); + assert_eq!(post, &tiny.all_bytes()[..]); + let unpost: TinyAsciiStr<$n> = postcard::from_bytes(&post).unwrap(); + assert_eq!(&*tiny, &*unpost); + } + }; +} + +test_roundtrip!(test_roundtrip4_1, 4, "en"); +test_roundtrip!(test_roundtrip4_2, 4, "Latn"); +test_roundtrip!(test_roundtrip8, 8, "calendar"); +test_roundtrip!(test_roundtrip16, 16, "verylongstring"); +test_roundtrip!(test_roundtrip10, 11, "shortstring"); +test_roundtrip!(test_roundtrip30, 24, "veryveryverylongstring");