konst-0.3.16/.cargo_vcs_info.json0000644000000001430000000000100122570ustar { "git": { "sha1": "942e3c79397c68e3c00a82c9f89189dabd8d5854" }, "path_in_vcs": "konst" }konst-0.3.16/Cargo.toml0000644000000046350000000000100102670ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.65.0" name = "konst" version = "0.3.16" authors = ["rodrimati1992 "] build = false include = [ "Cargo.toml", "src/**/*.rs", "../README.md", "LICENSE-ZLIB.md", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Const equivalents of std functions, compile-time comparison, and parsing" documentation = "https://docs.rs/konst/" readme = "README.md" keywords = [ "no-std", "const_fn", "parsing", ] categories = [ "no-std", "parsing", ] license = "Zlib" repository = "https://github.com/rodrimati1992/konst/" resolver = "1" [package.metadata.docs.rs] features = [ "docsrs", "alloc", "cmp", "parsing_proc", "rust_1_83", "rust_latest_stable", "nightly_mut_refs", ] [lib] name = "konst" path = "src/lib.rs" [dependencies.const_panic] version = "0.2.6" features = ["rust_1_64"] default-features = false [dependencies.konst_kernel] version = "=0.3.15" features = [ "rust_1_64", "__for_konst", ] [dependencies.konst_proc_macros] version = "=0.3.10" optional = true [dependencies.trybuild] version = "1.0" optional = true [dependencies.typewit] version = "1.1" features = ["rust_1_61"] [dev-dependencies.rand] version = "0.8.4" features = ["small_rng"] default-features = false [features] __cp_derive = [ "const_panic/derive", "const_panic/non_basic", ] __ui = [ "trybuild", "rust_latest_stable", ] alloc = ["konst_kernel/alloc"] cmp = [] debug = ["konst_kernel/debug"] default = [ "cmp", "iter", "parsing_proc", ] docsrs = ["konst_kernel/docsrs"] iter = ["konst_kernel/iter"] mut_refs = [ "rust_latest_stable", "konst_kernel/mut_refs", ] nightly_mut_refs = [ "mut_refs", "konst_kernel/nightly_mut_refs", ] parsing = [] parsing_proc = [ "parsing", "konst_proc_macros", ] rust_1_83 = ["konst_kernel/rust_1_83"] rust_latest_stable = ["rust_1_83"] konst-0.3.16/Cargo.toml.orig000064400000000000000000000037241046102023000137460ustar 00000000000000[package] name = "konst" version = "0.3.16" authors = ["rodrimati1992 "] rust-version = "1.65.0" edition = "2021" license = "Zlib" description = "Const equivalents of std functions, compile-time comparison, and parsing" documentation = "https://docs.rs/konst/" readme="../README.md" keywords = ["no-std", "const_fn", "parsing"] categories = ["no-std", "parsing"] repository = "https://github.com/rodrimati1992/konst/" include = [ "Cargo.toml", "src/**/*.rs", "../README.md", "LICENSE-ZLIB.md", ] [dependencies.konst_proc_macros] version = "=0.3.10" path = "../konst_proc_macros" optional = true [dependencies.konst_kernel] version = "=0.3.15" path = "../konst_kernel" features = ["rust_1_64", "__for_konst"] [dev-dependencies.rand] version = "0.8.4" default-features = false features = ["small_rng"] # dev-dependencies can't be optional [dependencies.trybuild] version = "1.0" optional = true [dependencies.typewit] version = "1.1" features = ["rust_1_61"] [dependencies.const_panic] version = "0.2.6" features = ["rust_1_64"] default-features = false [features] default = ["cmp", "iter", "parsing_proc"] # Enables extra checks for debug debug = ["konst_kernel/debug"] cmp = [] iter = ["konst_kernel/iter"] parsing_proc = ["parsing", "konst_proc_macros"] parsing = [] mut_refs = ["rust_latest_stable", "konst_kernel/mut_refs"] nightly_mut_refs = ["mut_refs", "konst_kernel/nightly_mut_refs"] rust_1_83 = ["konst_kernel/rust_1_83"] rust_latest_stable = ["rust_1_83"] alloc = ["konst_kernel/alloc"] # Enables ui tests, which are intended for the latest stable release. # This is not enabled in CI, because it's way too sensitive to # changes in how rustc formats errors __ui = ["trybuild", "rust_latest_stable"] __cp_derive = ["const_panic/derive", "const_panic/non_basic"] docsrs = ["konst_kernel/docsrs"] [package.metadata.docs.rs] features = ["docsrs", "alloc", "cmp", "parsing_proc", "rust_1_83", "rust_latest_stable", "nightly_mut_refs"] konst-0.3.16/LICENSE-ZLIB.md000064400000000000000000000015271046102023000132200ustar 00000000000000Copyright (c) 2021 Matias Rodriguez. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.konst-0.3.16/README.md000064400000000000000000000210021046102023000123230ustar 00000000000000[![Rust](https://github.com/rodrimati1992/konst/workflows/Rust/badge.svg)](https://github.com/rodrimati1992/konst/actions) [![crates-io](https://img.shields.io/crates/v/konst.svg)](https://crates.io/crates/konst) [![api-docs](https://docs.rs/konst/badge.svg)](https://docs.rs/konst/*) Const equivalents of std functions and const parsing. # Features This crate provides: - Const fn equivalents of standard library functions and methods. - [`destructure`] macro to allow destructuring types in const without getting "cannot drop in const" errors. - Compile-time parsing through the [`Parser`] type, and [`parser_method`] macro. # Examples ### Parsing an enum This example demonstrates how you can parse a simple enum from an environment variable, at compile-time. ```rust use konst::{ eq_str, option, result::unwrap_ctx, }; #[derive(Debug, PartialEq)] enum Direction { Forward, Backward, Left, Right, } impl Direction { const fn try_parse(input: &str) -> Result { // As of Rust 1.65.0, string patterns don't work in const contexts match () { _ if eq_str(input, "forward") => Ok(Direction::Forward), _ if eq_str(input, "backward") => Ok(Direction::Backward), _ if eq_str(input, "left") => Ok(Direction::Left), _ if eq_str(input, "right") => Ok(Direction::Right), _ => Err(ParseDirectionError), } } } const CHOICE: &str = option::unwrap_or!(option_env!("chosen-direction"), "forward"); const DIRECTION: Direction = unwrap_ctx!(Direction::try_parse(CHOICE)); fn main() { match DIRECTION { Direction::Forward => assert_eq!(CHOICE, "forward"), Direction::Backward => assert_eq!(CHOICE, "backward"), Direction::Left => assert_eq!(CHOICE, "left"), Direction::Right => assert_eq!(CHOICE, "right"), } } #[derive(Debug, PartialEq)] pub struct ParseDirectionError; use std::fmt::{self, Display}; impl Display for ParseDirectionError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Failed to parse a Direction") } } impl ParseDirectionError { const fn panic(&self) -> ! { panic!("failed to parse a Direction") } } ``` ### Parsing CSV This example demonstrates how CSV can be parsed into integers. This example requires the `"parsing"` and `"iter"` features (both are enabled by default). ```rust use konst::{ primitive::parse_u64, result::unwrap_ctx, iter, string, }; const CSV: &str = "3, 8, 13, 21, 34"; static PARSED: [u64; 5] = iter::collect_const!(u64 => string::split(CSV, ","), map(string::trim), map(|s| unwrap_ctx!(parse_u64(s))), ); assert_eq!(PARSED, [3, 8, 13, 21, 34]); ``` ### Parsing a struct This example demonstrates how a key-value pair format can be parsed into a struct. This requires the `"parsing"` feature (enabled by default). ```rust use konst::{ parsing::{Parser, ParseValueResult}, eq_str, for_range, parser_method, try_, unwrap_ctx, }; const PARSED: Struct = { // You can also parse strings from environment variables, or from an `include_str!(....)` let input = "\ colors = red, blue, green, blue amount = 1000 repeating = circle name = bob smith "; unwrap_ctx!(parse_struct(Parser::new(input))).0 }; fn main(){ assert_eq!( PARSED, Struct{ name: "bob smith", amount: 1000, repeating: Shape::Circle, colors: [Color::Red, Color::Blue, Color::Green, Color::Blue], } ); } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Struct<'a> { pub name: &'a str, pub amount: usize, pub repeating: Shape, pub colors: [Color; 4], } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Shape { Circle, Square, Line, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Color { Red, Blue, Green, } pub const fn parse_struct(mut parser: Parser<'_>) -> ParseValueResult<'_, Struct<'_>> { let mut name = ""; let mut amount = 0; let mut repeating = Shape::Circle; let mut colors = [Color::Red; 4]; parser = parser.trim_end(); if !parser.is_empty() { loop { let mut prev_parser = parser.trim_start(); parser = try_!(parser.find_skip('=')); parser_method!{prev_parser, strip_prefix; "name" => (name, parser) = try_!(parser.trim_start().split_keep('\n')), "amount" => (amount, parser) = try_!(parser.trim_start().parse_usize()), "repeating" => (repeating, parser) = try_!(parse_shape(parser.trim_start())), "colors" => (colors, parser) = try_!(parse_colors(parser.trim_start())), _ => { let err = &"could not parse Struct field name"; return Err(prev_parser.into_other_error(err)); } } if parser.is_empty() { break } parser = try_!(parser.strip_prefix("\n")); } } Ok((Struct{name, amount, repeating, colors}, parser)) } pub const fn parse_shape(mut parser: Parser<'_>) -> ParseValueResult<'_, Shape> { let shape = parser_method!{parser, strip_prefix; "circle" => Shape::Circle, "square" => Shape::Square, "line" => Shape::Line, _ => return Err(parser.into_other_error(&"could not parse Shape")) }; Ok((shape, parser)) } pub const fn parse_colors( mut parser: Parser<'_>, ) -> ParseValueResult<'_, [Color; LEN]> { let mut colors = [Color::Red; LEN]; for_range!{i in 0..LEN => (colors[i], parser) = try_!(parse_color(parser.trim_start())); match parser.strip_prefix(",") { Ok(next) => parser = next, Err(_) if i == LEN - 1 => {} Err(e) => return Err(e), } } Ok((colors, parser)) } pub const fn parse_color(mut parser: Parser<'_>) -> ParseValueResult<'_, Color> { let color = parser_method!{parser, strip_prefix; "red" => Color::Red, "blue" => Color::Blue, "green" => Color::Green, _ => return Err(parser.into_other_error(&"could not parse Color")) }; Ok((color, parser)) } ``` # Cargo features These are the features of these crates: - `"iter"`(enabled by default): Enables all iteration items, including macros/functions that take/return iterators, - `"cmp"`(enabled by default): Enables all comparison functions and macros, the string equality and ordering comparison functions don't require this feature. - `"parsing_proc"`(enabled by default): Enables the `"parsing"` feature, compiles the `konst_proc_macros` dependency, and enables the [`parser_method`] macro. You can use this feature instead of `"parsing"` if the slightly longer compile times aren't a problem. - `"parsing"`(enabled by default): Enables the [`parsing`] module (for parsing from `&str` and `&[u8]`), the `primitive::parse_*` functions, `try_rebind`, and `rebind_if_ok` macros. - `"alloc"`: Enables items that use types from the [`alloc`] crate, including `Vec` and `String`. ### Rust release related None of thse features are enabled by default. - `"rust_latest_stable"`: enables the latest `"rust_1_*"` feature. Only recommendable if you can update the Rust compiler every stable release. - `"rust_1_83"`: Enables const functions that take mutable references, `array::{from_fn_, map_}` macros, and [`destructure`] macro. # No-std support `konst` is `#![no_std]`, it can be used anywhere Rust can be used. # Minimum Supported Rust Version `konst` requires Rust 1.65.0. Features that require newer versions of Rust, or the nightly compiler, need to be explicitly enabled with crate features. [`alloc`]: https://doc.rust-lang.org/alloc/ [`const_eq`]: https://docs.rs/konst/*/konst/macro.const_eq.html [`const_eq_for`]: https://docs.rs/konst/*/konst/macro.const_eq_for.html [`const_cmp`]: https://docs.rs/konst/*/konst/macro.const_cmp.html [`const_cmp_for`]: https://docs.rs/konst/*/konst/macro.const_cmp_for.html [`polymorphism`]: https://docs.rs/konst/*/konst/polymorphism/index.html [`parsing`]: https://docs.rs/konst/*/konst/parsing/index.html [`primitive`]: https://docs.rs/konst/*/konst/primitive/index.html [`parser_method`]: https://docs.rs/konst/*/konst/macro.parser_method.html [`Parser`]: https://docs.rs/konst/*/konst/parsing/struct.Parser.html [`Parser::parse_u128`]: https://docs.rs/konst/*/konst/parsing/struct.Parser.html#method.parse_u128 [`destructure`]: https://docs.rs/konst/*/konst/macro.destructure.htmlkonst-0.3.16/src/__for_cmp_impls.rs000064400000000000000000000017261046102023000153430ustar 00000000000000use core::cmp::Ordering; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct U8Ordering(pub u8); impl U8Ordering { pub const LESS: Self = Self(0); pub const GREATER: Self = Self(1); pub const EQUAL: Self = Self(2); //#[inline] pub const fn to_ordering(self) -> Ordering { match self { Self::LESS => Ordering::Less, Self::GREATER => Ordering::Greater, _ => Ordering::Equal, } } //#[inline] pub const fn from_ordering(n: Ordering) -> Self { Self((n as u8) + 1) } } #[doc(hidden)] #[macro_export] macro_rules! __priv_ret_if_ne { ($left:expr, $right:expr) => {{ let l = $left; let r = $right; if l != r { return $crate::__::U8Ordering((l > r) as u8); } }}; } #[doc(hidden)] #[macro_export] macro_rules! __priv_first_expr { ($expr:expr) => { $expr }; ($expr:expr, $($more:expr),*) => { $expr }; } konst-0.3.16/src/alloc_type.rs000064400000000000000000000063161046102023000143470ustar 00000000000000//! Generic constants for types from the [`alloc`] crate, including `String` and `Vec`. //! //! [`alloc`]: https://doc.rust-lang.org/alloc/ //! use alloc::{borrow::Cow, string::String, vec::Vec}; /// An empty `Cow<'_, str>`. Usable to construct a `[Cow<'_, str>; N]`. /// /// As of Rust 1.65.0, `[Cow::Borrowed(""); LEN]` is not valid, /// because `Cow<'_, str>` isn't copy, /// but `[COW_STR_NEW; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::alloc_type::COW_STR_NEW; /// /// use std::borrow::Cow; /// /// const SIX_COWS: [Cow<'_, str>; 6] = [COW_STR_NEW; 6]; /// /// let mut cows = SIX_COWS; /// /// ('a'..='f') /// .enumerate() /// .filter(|(i, _)| i % 2 == 0 ) /// .for_each(|(i, c)|{ /// cows[i].to_mut().push(c) /// }); /// /// assert_eq!(cows, ["a", "", "c", "", "e", ""]) /// /// ``` /// pub const COW_STR_NEW: Cow<'_, str> = Cow::Borrowed(""); /// An empty `String`. Usable to construct a `[String; N]`. /// /// As of Rust 1.65.0, `[String::new(); LEN]` is not valid, because `String` isn't copy, /// but `[STRING_NEW; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::alloc_type::STRING_NEW; /// /// const STRINGS: [String; 3] = [STRING_NEW; 3]; /// /// let mut strings = STRINGS; /// /// strings[0].push_str("foo"); /// strings[1].push_str("bar"); /// strings[2].push_str("baz"); /// /// assert_eq!(strings, ["foo", "bar", "baz"]); /// /// /// ``` /// pub const STRING_NEW: String = String::new(); declare_generic_const! { /// An empty `Cow<'_, [T]>`. Usable to construct a `[Cow<'_, [T]>; N]`. /// /// As of Rust 1.65.0, `[Cow::Borrowed(&[][..]); LEN]` is not valid, /// because `Cow<'_, [T]>` isn't copy, /// but `[CONST; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::alloc_type::COW_SLICE_NEW; /// /// use std::borrow::Cow; /// /// const SLICES: [Cow<'_, [u64]>; 6] = [COW_SLICE_NEW::::V; 6]; /// /// let mut cows = SLICES; /// /// [3, 5, 8, 13, 21, 34].iter().copied() /// .enumerate() /// .filter(|(i, _)| i % 2 != 0 ) /// .for_each(|(i, v)|{ /// cows[i].to_mut().push(v) /// }); /// /// assert_eq!(cows, [&[][..], &[5], &[], &[13], &[], &[34]]) /// /// ``` /// for['a, T: Clone + 'a] pub const COW_SLICE_NEW['a, T]: Cow<'a, [T]> = Cow::Borrowed(&[]); } declare_generic_const! { /// An empty `Vec`. Usable to construct a `[Vec; N]`. /// /// As of Rust 1.65.0, `[Vec::new(); LEN]` is not valid, /// because `Vec` isn't copy, /// but `[CONST; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::alloc_type::VEC_NEW; /// /// use std::borrow::Cow; /// /// const VECS: [Vec; 3] = [VEC_NEW::::V; 3]; /// /// let mut vecs = VECS; /// /// vecs[0].extend_from_slice(&[3]); /// vecs[1].extend_from_slice(&[5, 8]); /// vecs[2].extend_from_slice(&[13, 21, 34]); /// /// assert_eq!(vecs, [&[3][..], &[5, 8], &[13, 21, 34]]); /// /// ``` /// for[T] pub const VEC_NEW[T]: Vec = Vec::new(); } konst-0.3.16/src/array/__array_macros_2.rs000064400000000000000000000042461046102023000165330ustar 00000000000000 #[doc(hidden)] #[macro_export] macro_rules! __array_map_by_val { ($array:expr, $($closure:tt)* ) => ( $crate::__::__parse_closure_1!{ ($crate::__array_map2__with_parsed_closure) ($array,) (array_map), $($closure)* } ); } #[doc(hidden)] #[macro_export] macro_rules! __array_map2__with_parsed_closure { ( $array:expr, ($($pattern:tt)*) $(-> $ret:ty)? $mapper:block $(,)? ) => (match $crate::array::ArrayConsumer::new($array) { mut consumer => { let mut builder = $crate::array::ArrayBuilder::new(); builder.infer_length_from_consumer(&consumer); while let Some(elem) = consumer.next() { let elem = $crate::__::ManuallyDrop::into_inner(elem); let $($pattern)* = elem; let mapped $(: $ret)? = $mapper; builder.push(mapped); } $crate::__::mem::forget(consumer); builder.build() } }) } #[doc(hidden)] #[macro_export] macro_rules! __array_from_fn2 { ($($args:tt)*) => ({ $crate::__::__split_array_type_and_closure!{ (($crate::__array_from_fn2__splitted_type_and_closure) ()) () ($($args)*) } }); } #[doc(hidden)] #[macro_export] macro_rules! __array_from_fn2__splitted_type_and_closure { ($type:tt $($closure_unparsed:tt)*) => { $crate::__::__parse_closure_1!{ ($crate::__array_from_fn_with_parsed_closure) ($type) (from_fn_), $($closure_unparsed)* } } } #[doc(hidden)] #[macro_export] macro_rules! __array_from_fn_with_parsed_closure { ( ($($($type:tt)+)?) ($($pattern:tt)*) $(-> $ret:ty)? $mapper:block $(,)? ) => ({ let mut i = 0usize; let arr $(: $crate::__::__unparenthesize_ty!($($type)*))? = $crate::__array_map2__with_parsed_closure!{ $crate::__::unit_array(), (()) $(-> $ret)? { let $($pattern)* = i; i+=1; $mapper } }; arr }); } konst-0.3.16/src/array/array_builder.rs000064400000000000000000000153751046102023000161630ustar 00000000000000use core::fmt::{self, Debug}; use core::mem::{ManuallyDrop, MaybeUninit}; use crate::array::ArrayConsumer; /// For constructing an array element by element. /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// assert_eq!(ARR, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]); /// /// const ARR: [u32; 10] = { /// let mut builder = ArrayBuilder::new(); /// builder.push(1); /// builder.push(1); /// /// while !builder.is_full() { /// let [.., a, b] = *builder.as_slice() else { unreachable!() }; /// /// builder.push(a + b); /// } /// /// builder.build() /// }; /// ``` #[repr(C)] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub struct ArrayBuilder { array: [MaybeUninit; N], inited: usize, } impl ArrayBuilder { /// Constructs an empty ArrayBuilder pub const fn new() -> Self { ArrayBuilder { array: crate::maybe_uninit::uninit_array(), inited: 0, } } /// The amount of initialized elements in the array /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// let mut builder = ArrayBuilder::<_, 3>::new(); /// /// assert_eq!(builder.len(), 0); /// /// builder.push(3); /// assert_eq!(builder.len(), 1); /// /// builder.push(5); /// assert_eq!(builder.len(), 2); /// /// builder.push(8); /// assert_eq!(builder.len(), 3); /// ``` /// pub const fn len(&self) -> usize { self.inited } /// Whether the array has been fully initialized /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// let mut builder = ArrayBuilder::<_, 3>::new(); /// /// assert!(!builder.is_full()); /// /// builder.push(3); /// assert!(!builder.is_full()); /// /// builder.push(5); /// assert!(!builder.is_full()); /// /// builder.push(8); /// assert!(builder.is_full()); /// ``` /// pub const fn is_full(&self) -> bool { self.inited == N } /// Gets the initialized part of the array as a slice /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// let mut builder = ArrayBuilder::<_, 3>::new(); /// /// assert_eq!(builder.as_slice(), [].as_slice()); /// /// builder.push(3); /// assert_eq!(builder.as_slice(), [3].as_slice()); /// /// builder.push(5); /// assert_eq!(builder.as_slice(), [3, 5].as_slice()); /// /// builder.push(8); /// assert_eq!(builder.as_slice(), [3, 5, 8].as_slice()); /// ``` /// pub const fn as_slice(&self) -> &[T] { // SAFETY: self.array is guaranteed initialized up to self.inited - 1 inclusive unsafe { core::slice::from_raw_parts(self.array.as_ptr().cast::(), self.inited) } } /// Gets the initialized part of the array as a mutable slice /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// let mut builder = ArrayBuilder::<_, 3>::new(); /// /// assert_eq!(builder.as_mut_slice(), [].as_mut_slice()); /// /// builder.push(3); /// assert_eq!(builder.as_mut_slice(), [3].as_mut_slice()); /// /// builder.push(5); /// assert_eq!(builder.as_mut_slice(), [3, 5].as_mut_slice()); /// /// builder.push(8); /// assert_eq!(builder.as_mut_slice(), [3, 5, 8].as_mut_slice()); /// ``` /// pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: self.array is guaranteed initialized up to self.inited - 1 inclusive unsafe { core::slice::from_raw_parts_mut(self.array.as_mut_ptr().cast::(), self.inited) } } /// Appends `val` to the array. /// /// # Panic /// /// Panics if `self.len() == N`, i.e.: the array is fully initialized. /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// let mut builder = ArrayBuilder::<_, 3>::new(); /// /// builder.push(3); /// builder.push(5); /// builder.push(8); /// /// assert_eq!(builder.build(), [3, 5, 8]); /// ``` /// pub const fn push(&mut self, val: T) { assert!(self.inited < N, "trying to add an element to full array"); self.array[self.inited] = MaybeUninit::new(val); self.inited += 1; } /// Unwraps this ArrayBuilder into an array. /// /// # Panic /// /// Panics if `self.len() != N`, i.e.: the array is not fully initialized. /// /// # Example /// /// ```rust /// use konst::array::ArrayBuilder; /// /// assert_eq!(ARR, [3, 5, 8]); /// /// const ARR: [u8; 3] = { /// let mut builder = ArrayBuilder::new(); /// /// builder.push(3); /// builder.push(5); /// builder.push(8); /// /// builder.build() /// }; /// ``` /// pub const fn build(self) -> [T; N] { assert!(self.is_full(), "trying to unwrap a non-fully-initialized array"); // SAFETY: self.array is guaranteed fully initialized by the fact that // each element is inited in lockstep with incrementing self.inited by 1, // and the assertion above. unsafe { let mut this = ManuallyDrop::new(self); // this cast is guaranteed correct becaue this struct is `#[repr(C))]` // and the first field is a `[MaybeUninit; N]` (&raw mut this).cast::<[T; N]>().read() } } /// Gets a bitwise copy of this Builder, requires `T: Copy`. pub const fn copy(&self) -> Self where T: Copy { Self {..*self} } /// Helper for inferring the length of the built array from an [`ArrayConsumer`]. pub const fn infer_length_from_consumer(&self, _consumer: &ArrayConsumer) {} } impl Debug for ArrayBuilder { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("ArrayBuilder") .field("array", &self.as_slice()) .field("uninit_len", &(N - self.inited)) .finish() } } impl Clone for ArrayBuilder { fn clone(&self) -> Self { let mut this = Self::new(); for elem in self.as_slice() { this.push(elem.clone()); } this } } impl Drop for ArrayBuilder { fn drop(&mut self) { unsafe { let inited = self.inited; let ptr = self.array.as_mut_ptr().cast::(); core::ptr::slice_from_raw_parts_mut(ptr, inited).drop_in_place(); } } } konst-0.3.16/src/array/array_consumer.rs000064400000000000000000000220011046102023000163500ustar 00000000000000use core::fmt::{self, Debug}; use core::mem::{ManuallyDrop, MaybeUninit}; /// Const analog of [`core::array::IntoIter`] /// /// This isn't called `IntoIter` because it does not implement the [`ConstIntoIter`] trait, /// as this type does not have [the API that that trait requires]( /// https://docs.rs/konst/latest/konst/iter/trait.ConstIntoIter.html#isiteratorkind ) /// /// # Example /// /// ```rust /// use konst::array::{ArrayBuilder, ArrayConsumer}; /// /// use core::mem::ManuallyDrop as MD; /// /// assert_eq!(ARR, [21, 13, 8, 5, 3]); /// /// const ARR: [u32; 5] = reverse([3, 5, 8, 13, 21]); /// /// const fn reverse(arr: [T; LEN]) -> [T; LEN] { /// let mut iter = ArrayConsumer::new(arr); /// let mut builder = ArrayBuilder::new(); /// /// while let Some(item) = iter.next_back() { /// builder.push(MD::into_inner(item)); /// } /// /// // necessary to avoid "destructor cannot be evaluated at compile-time" error /// iter.assert_is_empty(); /// /// builder.build() /// } /// ``` /// /// [`ConstIntoIter`]: crate::iter::ConstIntoIter #[repr(C)] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub struct ArrayConsumer { array: [MaybeUninit; N], taken_front: usize, taken_back: usize, } impl ArrayConsumer { /// Constructs an ArrayConsumer from an array. pub const fn new(array: [T; N]) -> Self { Self { array: array_into_md(array), taken_front: 0, taken_back: 0, } } /// Constructs an already-consumed ArrayConsumer. /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// let mut iter = ArrayConsumer::::empty(); /// /// assert_eq!(iter.next(), None); /// /// ``` pub const fn empty() -> Self { Self { array: crate::maybe_uninit::uninit_array(), taken_front: N, taken_back: 0, } } const fn is_empty(&self) -> bool { (N - self.taken_front - self.taken_back) == 0 } const fn slice_len(&self) -> usize { N - self.taken_front - self.taken_back } /// Asserts that the ArrayConsumer is empty, /// allows using ArrayConsumer in const. /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// use core::mem::ManuallyDrop as MD; /// /// assert_eq!(SUM, 16); /// /// const SUM: u64 = summer(ArrayConsumer::new([3, 5, 8])); /// /// const fn summer(mut iter: ArrayConsumer) -> u64 { /// let mut sum = 0u64; /// while let Some(item) = iter.next() { /// sum += MD::into_inner(item); /// } /// iter.assert_is_empty(); /// sum /// } /// ``` #[track_caller] pub const fn assert_is_empty(self) { assert!(self.is_empty()); core::mem::forget(self); } /// Gets the remainder of the array as a slice /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// let mut iter = ArrayConsumer::new([3, 5, 8]); /// /// assert_eq!(iter.as_slice(), &[3, 5, 8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_slice(), &[5, 8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_slice(), &[8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_slice(), &[][..]); /// /// assert_eq!(iter.next(), None); /// assert_eq!(iter.as_slice(), &[][..]); /// ``` pub const fn as_slice(&self) -> &[T] { // SAFETY: self.array is guaranteed initialized starting from self.taken_front // up to `N - self.taken_back` unsafe { let ptr = self.array.as_ptr().add(self.taken_front).cast::(); core::slice::from_raw_parts(ptr, self.slice_len()) } } /// Gets the remainder of the array as a mutable slice /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// let mut iter = ArrayConsumer::new([3, 5, 8]); /// /// assert_eq!(iter.as_mut_slice(), &mut [3, 5, 8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_mut_slice(), &mut [5, 8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_mut_slice(), &mut [8][..]); /// /// assert!(iter.next().is_some()); /// assert_eq!(iter.as_mut_slice(), &mut [][..]); /// /// assert_eq!(iter.next(), None); /// assert_eq!(iter.as_mut_slice(), &mut [][..]); /// ``` pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: self.array is guaranteed initialized starting from self.taken_front // up to `N - self.taken_back` unsafe { let ptr = self.array.as_mut_ptr().add(self.taken_front).cast::(); core::slice::from_raw_parts_mut(ptr, self.slice_len()) } } /// Gets a bitwise copy of this ArrayConsumer, requires `T: Copy`. pub const fn copy(&self) -> Self where T: Copy { Self {..*self} } /// Gets the next element from the array /// /// Due to limitations of const eval as of Rust 1.83.0, /// this function returns a `ManuallyDrop` to be able to return a `T: Drop` in an `Option`, /// you'll need to call [`ManuallyDrop::into_inner`] to get `T` and avoid leaking it. /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// use std::mem::ManuallyDrop as MD; /// /// let mut iter = ArrayConsumer::new([3, 5, 8]); /// /// assert_eq!(iter.as_slice(), &[3, 5, 8][..]); /// /// assert_eq!(iter.next(), Some(MD::new(3))); /// assert_eq!(iter.as_slice(), &[5, 8][..]); /// /// assert_eq!(iter.next(), Some(MD::new(5))); /// assert_eq!(iter.as_slice(), &[8][..]); /// /// assert_eq!(iter.next(), Some(MD::new(8))); /// assert_eq!(iter.as_slice(), &[][..]); /// /// assert_eq!(iter.next(), None); /// assert_eq!(iter.as_slice(), &[][..]); /// ``` pub const fn next(&mut self) -> Option> { if self.is_empty() { return None; } // SAFETY: self.array[self.taken_front] is guaranteed initialized let ret = unsafe { self.array[self.taken_front].assume_init_read() }; self.taken_front += 1; Some(ManuallyDrop::new(ret)) } /// Gets the next element from the end of the array /// /// Due to limitations of const eval as of Rust 1.83.0, /// this function returns a `ManuallyDrop` to be able to return a `T: Drop` in an `Option`, /// you'll need to call [`ManuallyDrop::into_inner`] to get `T` and avoid leaking it. /// /// # Example /// /// ```rust /// use konst::array::ArrayConsumer; /// /// use std::mem::ManuallyDrop as MD; /// /// let mut iter = ArrayConsumer::new([3, 5, 8]); /// /// assert_eq!(iter.as_slice(), &[3, 5, 8][..]); /// /// assert_eq!(iter.next_back(), Some(MD::new(8))); /// assert_eq!(iter.as_slice(), &[3, 5][..]); /// /// assert_eq!(iter.next_back(), Some(MD::new(5))); /// assert_eq!(iter.as_slice(), &[3][..]); /// /// assert_eq!(iter.next_back(), Some(MD::new(3))); /// assert_eq!(iter.as_slice(), &[][..]); /// /// assert_eq!(iter.next_back(), None); /// assert_eq!(iter.as_slice(), &[][..]); /// ``` pub const fn next_back(&mut self) -> Option> { if self.is_empty() { return None; } let index = N - self.taken_back - 1; // SAFETY: self.array[index] is guaranteed initialized let ret = unsafe { self.array[index].assume_init_read() }; self.taken_back += 1; Some(ManuallyDrop::new(ret)) } } impl Debug for ArrayConsumer { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(self.as_slice(), fmt) } } impl Clone for ArrayConsumer { fn clone(&self) -> Self { let mut this = Self { array: crate::maybe_uninit::uninit_array(), taken_front: 0, taken_back: N, }; for (i, elem) in self.as_slice().iter().cloned().enumerate() { this.array[i] = MaybeUninit::new(elem); this.taken_back -= 1; } this } } impl Drop for ArrayConsumer { fn drop(&mut self) { unsafe { let slice_len = self.slice_len(); let ptr = self.array.as_mut_ptr().cast::(); core::ptr::slice_from_raw_parts_mut(ptr.add(self.taken_front), slice_len).drop_in_place(); } } } #[doc(hidden)] const fn array_into_md(arr: [T; N]) -> [MaybeUninit; N] { unsafe { crate::__::__priv_transmute! {[T; N], [MaybeUninit; N], arr} } } konst-0.3.16/src/array.rs000064400000000000000000000125321046102023000133270ustar 00000000000000//! Const equivalents of array functions. macro_rules! leak_warning { () => { concat!( "# Warning\n", "\n", "This macro leaks the initialized part of the array\n", "if the closure passed to this macro panics or returns early.\n", "\n", "note: this warning is not relevant if the elements don't need dropping", "(e.g: by implementing `Copy`).\n" ) }; } use leak_warning; /// Superceeded by [`map_`], /// const version of [`array::map`](https://doc.rust-lang.org/std/primitive.array.html#method.map). /// #[doc = leak_warning!()] /// /// # Limitations /// /// This macro supports mapping from non-Copy arrays if any of these /// conditions are met about the parameter of the passed-in closure: /// 1. it's a pattern that only copies Copy fields of each array element /// 2. it's a `ref` pattern /// /// [examples of both of the above conditions below](#map-noncopy-example) /// /// # Example /// /// ### Basic /// /// ```rust /// use konst::array; /// /// const TRIMMED: [&str; 3] = array::map!([" foo", "bar ", " baz "], konst::string::trim); /// assert_eq!(TRIMMED, ["foo", "bar", "baz"]); /// /// const LENGTHS: [usize; 3] = array::map!(["foo", "hello", "bar baz"], |s| s.len()); /// assert_eq!(LENGTHS, [3, 5, 7]); /// /// const SQUARED: [u32; 6] = array::map!([1, 2, 3, 4, 5, 6], |x: u32| x.pow(2)); /// assert_eq!(SQUARED, [1, 4, 9, 16, 25, 36]); /// /// { /// let input = [3, 5, 8]; /// let output = array::map!(input, |x| -> u64 { x + 2 }); /// assert_eq!(output, [5, 7, 10]); /// } /// /// ``` /// /// /// ### Map from non-Copy array /// /// Demonstrates both ways to map from a non-Copy array. /// /// ```rust /// use konst::array; /// /// struct NonCopy(u32, u32); /// /// const PRIME_SUMS: [u32; 3] = { /// let input = [NonCopy(2, 3), NonCopy(5, 7), NonCopy(11, 13)]; /// /// // demonstrates the first way to map from non-Copy elements /// array::map!(input, |NonCopy(l, r)| l + r) /// }; /// assert_eq!(PRIME_SUMS, [5, 12, 24]); /// /// const FIBB_SUMS: [u32; 3] = { /// let input = [NonCopy(2, 3), NonCopy(5, 8), NonCopy(13, 21)]; /// /// // demonstrates the second way to map from non-Copy elements /// array::map!(input, |ref nc| nc.0 + nc.1) /// }; /// assert_eq!(FIBB_SUMS, [5, 13, 34]); /// /// ``` /// pub use konst_kernel::array_map as map; #[cfg(feature = "rust_1_83")] #[doc(hidden)] pub mod __array_macros_2; #[cfg(feature = "rust_1_83")] mod array_builder; #[cfg(feature = "rust_1_83")] mod array_consumer; #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub use self::{ array_builder::ArrayBuilder, array_consumer::ArrayConsumer, }; #[cfg(feature = "rust_1_83")] macro_rules! drop_warning { () => { concat!( "# Note", "\n\n", "`return` inside the closure passed to this macro ", "attempts to return from the function where this macro is called, ", "which drops the array elements, ", "and dropping isn't allowed in const as of Rust 1.83.0.", "\n\n", "The same applies to `?`, ", "and labelled `break`/`continue` into labels from outside the closure.", ) }; } #[cfg(feature = "rust_1_83")] use drop_warning; /// Const equivalent of /// [`array::map`](https://doc.rust-lang.org/std/primitive.array.html#method.map) /// #[doc = drop_warning!()] /// /// # Example /// /// ```rust /// assert_eq!(PAIRS, [(3, "hello"), (5, "world"), (8, "foo")]); /// /// const PAIRS: [(u8, &str); 3] = /// swap_pairs([("hello", 3), ("world", 5), ("foo", 8)]); /// /// const fn swap_pairs(pairs: [(T, U); N]) -> [(U, T); N] { /// konst::array::map_!(pairs, |pair: (T, U)| { /// // need to use `destructure` to destructure types that may contain Drop fields /// konst::destructure!{(a, b) = pair} /// (b, a) /// }) /// } /// ``` /// #[doc(inline)] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub use crate::__array_map_by_val as map_; /// Superceeded by [`from_fn_`], const version of /// [`array::from_fn`](core::array::from_fn). /// #[doc = leak_warning!()] /// /// # Example /// /// ```rust /// use konst::array; /// /// { /// const POWERS: [u64; 5] = array::from_fn!(|i| 2u64.pow(i as u32)); /// /// assert_eq!(POWERS, [1, 2, 4, 8, 16]); /// } /// /// // Annotating the array type /// assert_eq!( /// array::from_fn!([&str; 6] => |i| konst::string::str_up_to("hello", i)), /// ["", "h", "he", "hel", "hell", "hello"], /// ); /// ``` /// pub use konst_kernel::array_from_fn as from_fn; /// Const equivalent of [`array::from_fn`](core::array::from_fn). /// #[doc = drop_warning!()] /// /// /// # Example /// /// ```rust /// use konst::array; /// /// { /// const POWERS: [u64; 5] = array::from_fn_!(|i| 2u64.pow(i as u32)); /// /// assert_eq!(POWERS, [1, 2, 4, 8, 16]); /// } /// /// // Annotating the array type /// assert_eq!( /// array::from_fn_!([&str; 6] => |i| konst::string::str_up_to("hello", i)), /// ["", "h", "he", "hel", "hell", "hello"], /// ); /// ``` /// #[doc(inline)] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub use crate::__array_from_fn2 as from_fn_; konst-0.3.16/src/chr.rs000064400000000000000000000033221046102023000127620ustar 00000000000000//! Const equivalents of `char` functions. //! //! The module is called `chr` to avoid name collisions with the `char` type. /// A char encoded as a utf8 string. /// /// # Example /// /// ```rust /// use konst::chr; /// /// const ENC: &chr::Utf8Encoded = &chr::encode_utf8('û'); /// const ENC_STR: &str = ENC.as_str(); /// /// assert_eq!(ENC_STR, "û"); /// /// ``` pub use konst_kernel::chr::Utf8Encoded; /// Encodes `c` into utf8, const analog of [`char::encode_utf8`]. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::chr; /// /// const ENC: &chr::Utf8Encoded = &chr::encode_utf8('🤔'); /// const ENC_STR: &str = ENC.as_str(); /// /// assert_eq!(ENC_STR, "🤔"); /// /// ``` pub use konst_kernel::chr::encode_utf8; /// Unsafely coerces `u32` to `char`, /// const equivalent of [`char::from_u32_unchecked`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.82.0. /// /// # Safety /// /// The input `u32` must be within either of these ranges: /// /// - `0..=0xD7FF` /// - `0xE000..=0x10FFFF` /// /// # Example /// /// ```rust /// use konst::chr; /// /// const AT: char = unsafe { chr::from_u32_unchecked(64) }; /// /// assert_eq!(AT, '@'); /// ``` pub use konst_kernel::chr::from_u32_unchecked; /// Fallible conversion from `u32` to `char`, /// const equivalent of [`char::from_u32`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.67.0. /// /// # Example /// /// ```rust /// use konst::{chr, option}; /// /// const AT: char = option::unwrap!(chr::from_u32(64)); /// /// assert_eq!(AT, '@'); /// ``` pub use konst_kernel::chr::from_u32; konst-0.3.16/src/cmp/cmp_wrapper.rs000064400000000000000000000047321046102023000153120ustar 00000000000000use crate::cmp::{ConstCmp, IsAConstCmp, IsNotStdKind, IsStdKind}; /// A wrapper type for std types, which defines `const_eq` and `const_cmp` methods for them. /// /// This is what [`coerce_to_cmp`](crate::coerce_to_cmp) /// and the comparison macros convert standard library types into. /// /// # Example /// /// ```rust /// use konst::{ /// cmp::CmpWrapper, /// coerce_to_cmp, /// }; /// /// use std::cmp::Ordering; /// /// { /// // The `CmpWrapper` type annotation is just for the reader /// let foo: CmpWrapper = coerce_to_cmp!(10u32); /// assert!( foo.const_eq(&10)); /// assert!(!foo.const_eq(&20)); /// /// assert_eq!(foo.const_cmp(&5), Ordering::Greater); /// assert_eq!(foo.const_cmp(&10), Ordering::Equal); /// assert_eq!(foo.const_cmp(&15), Ordering::Less); /// } /// { /// let bar = CmpWrapper(Ordering::Equal); /// assert!( bar.const_eq(&Ordering::Equal)); /// assert!(!bar.const_eq(&Ordering::Less)); /// /// assert_eq!(bar.const_cmp(&Ordering::Less), Ordering::Greater); /// assert_eq!(bar.const_cmp(&Ordering::Equal), Ordering::Equal); /// assert_eq!(bar.const_cmp(&Ordering::Greater), Ordering::Less); /// } /// /// ``` #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct CmpWrapper(pub T); impl<'a, T> CmpWrapper<&'a [T]> { /// For constructing from a reference to an array. /// /// With slices you can do `CmpWrapper(slice)` as well. #[inline(always)] pub const fn slice(x: &'a [T]) -> Self { Self { 0: x } } } impl

ConstCmp for CmpWrapper

{ type Kind = IsNotStdKind; } macro_rules! std_kind_impls { ($($ty:ty),* $(,)* ) => ( $( impl ConstCmp for $ty { type Kind = IsStdKind; } impl IsAConstCmp { /// Copies the value from `reference`, and wraps it in a `CmpWrapper` #[inline(always)] pub const fn coerce(self, reference: &$ty) -> CmpWrapper<$ty> { CmpWrapper(*reference) } } impl CmpWrapper<$ty> { /// Compares `self` and `other` for equality. #[inline(always)] pub const fn const_eq(self, other: &$ty) -> bool { self.0 == *other } } )* ) } std_kind_impls! { i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, bool, char, } konst-0.3.16/src/cmp/const_cmp.rs000064400000000000000000000206371046102023000147620ustar 00000000000000use crate::cmp::{CmpWrapper, IsNotStdKind, IsRefKind, IsStdKind}; use core::marker::PhantomData; //////////////////////////////////////////////////////////////////////////////// /// Marker trait for types that implement the const comparison methods. /// /// # Implementors /// /// Types that implement this trait are also expected to implement at least one of /// these inherent methods: /// /// ```rust /// use std::cmp::Ordering; /// /// # struct Foo; /// # impl Foo { /// const fn const_eq(&self, other: &Self) -> bool /// # { true } /// /// const fn const_cmp(&self, other: &Self) -> Ordering /// # { Ordering::Equal } /// # } /// /// ``` /// /// # Coercions /// /// The [`Kind`](#associatedtype.Kind) associated type /// is used in the [`IsAConstCmp`] marker type /// to automatically wrap types in [`CmpWrapper`] if they're from the standard library, /// otherwise leaving them unwrapped. /// /// /// # Example /// /// ### Manual Implementation /// /// ``` /// use konst::{ /// cmp::{ConstCmp, IsNotStdKind}, /// const_cmp, const_eq, try_equal, /// }; /// /// use std::cmp::Ordering; /// /// /// struct MyType { /// x: &'static str, /// y: &'static [u16], /// } /// /// impl ConstCmp for MyType { /// type Kind = IsNotStdKind; /// } /// /// impl MyType { /// pub const fn const_eq(&self, other: &Self) -> bool { /// const_eq!(self.x, other.x) && /// const_eq!(self.y, other.y) /// } /// /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// try_equal!(const_cmp!(self.x, other.x)); /// try_equal!(const_cmp!(self.y, other.y)) /// } /// } /// /// const _: () = { /// let foo = MyType{x: "hello", y: &[3, 5, 8, 13]}; /// let bar = MyType{x: "world", y: &[3, 5, 8, 13]}; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(const_eq!(foo, foo)); /// assert!(!const_eq!(foo, bar)); /// }; /// ``` /// /// /// ### `ìmpl_cmp`-based Implementation /// /// You can use [`impl_cmp`] to implement this trait, /// as well as define the same methods for /// multiple implementations with different type arguments. /// /// ``` /// use konst::{const_cmp, const_eq, impl_cmp, try_equal}; /// /// use std::cmp::Ordering; /// /// /// struct MyType<'a, T> { /// x: &'a str, /// y: &'a [T], /// } /// /// impl_cmp!{ /// // The comparison functions are only implemented for these types. /// impl['a] MyType<'a, bool>; /// impl['a] MyType<'a, u16>; /// impl['a] MyType<'a, &'static str>; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// const_eq!(self.x, other.x) && /// const_eq!(self.y, other.y) /// } /// /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// try_equal!(const_cmp!(self.x, other.x)); /// try_equal!(const_cmp!(self.y, other.y)) /// } /// } /// /// const _: () = { /// let foo = MyType{x: "hello", y: &[3, 5, 8, 13]}; /// let bar = MyType{x: "world", y: &[3, 5, 8, 13]}; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(const_eq!(foo, foo)); /// assert!(!const_eq!(foo, bar)); /// }; /// /// const _: () = { /// let foo = MyType{x: "hello", y: &[false]}; /// let bar = MyType{x: "hello", y: &[true]}; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(const_eq!(foo, foo)); /// assert!(!const_eq!(foo, bar)); /// }; /// /// ``` /// /// [`CmpWrapper`]: struct.CmpWrapper.html /// [`impl_cmp`]: ../macro.impl_cmp.html pub trait ConstCmp { /// What kind of type this is, this can be one of: /// /// - [`IsStdKind`]: A standard library type. /// /// - [`IsRefKind`]: A reference type. /// /// - [`IsNotStdKind`]: A type that is not from the standard library. /// type Kind; } /////////////////////////////////////////////////////////////////////////////// impl ConstCmp for [T; N] { type Kind = IsStdKind; } impl ConstCmp for [T] { type Kind = IsStdKind; } impl ConstCmp for str { type Kind = IsStdKind; } impl ConstCmp for &T where T: ?Sized + ConstCmp, { type Kind = IsRefKind; } impl ConstCmp for &mut T where T: ?Sized + ConstCmp, { type Kind = IsRefKind; } /////////////////////////////////////////////////////////////////////////////// /// A helper trait of [`ConstCmp`], used for dereferencing. pub trait ConstCmpUnref: ConstCmp { /// What type `Self` becomes after removing all layers of references. /// /// Examples: /// - `u32::This == u32` /// - `<&u32>::This == u32` /// - `<&&u32>::This == u32` type This: ?Sized + ConstCmp; } impl ConstCmpUnref for T where T: ?Sized + ConstCmp, T: ConstCmpUnrefHelper<::Kind>, T::This_: ConstCmp, { type This = T::This_; } /// An implementation detail of [`ConstCmpUnref`]. pub trait ConstCmpUnrefHelper { type This_: ?Sized; } impl ConstCmpUnrefHelper for T { type This_ = T; } impl ConstCmpUnrefHelper for T { type This_ = T; } impl ConstCmpUnrefHelper for &T { type This_ = T::This; } impl ConstCmpUnrefHelper for &mut T { type This_ = T::This; } /////////////////////////////////////////////////////////////////////////////// /// Hack used to automatically wrap standard library types inside [`CmpWrapper`], /// while leaving user defined types unwrapped. /// /// This can be constructed with he [`NEW` associated constant](#associatedconstant.NEW) /// /// # Type parameters /// /// `K` is `::Kind` /// The kind of type that `T` is: either [`IsStdKind`] or /// [`IsNotStdKind`](crate::cmp::IsNotStdKind). /// /// `T` is `::This`, /// the `R` type after removing all layers of references. /// /// `R`: Is a type that implements [`ConstCmp`] /// #[allow(clippy::type_complexity)] pub struct IsAConstCmp( PhantomData<( PhantomData PhantomData>, PhantomData PhantomData>, PhantomData PhantomData>, )>, ); impl Copy for IsAConstCmp {} impl Clone for IsAConstCmp { fn clone(&self) -> Self { *self } } impl IsAConstCmp where R: ?Sized + ConstCmpUnref, T: ?Sized + ConstCmp, { /// Constructs an `IsAConstCmp` pub const NEW: Self = Self(PhantomData); } impl IsAConstCmp { /// Infers the type parameters by taking a reference to `R` . /// /// The `K` and `T` type parameters are determined by `R` in /// the [`NEW`] associated constant. /// /// [`NEW`]: #associatedconstant.NEW #[inline(always)] pub const fn infer_type(self, _: &R) -> Self { self } /// Removes layers of references by coercing the argument. #[inline(always)] pub const fn unreference(self, r: &T) -> &T { r } } ///////////////////////////////////////////////////////////////////////////// impl IsAConstCmp { /// An identity function, just takes `reference` and returns it. #[inline(always)] pub const fn coerce(self, reference: &T) -> &T { reference } } ///////////////////////////////////////////////////////////////////////////// impl IsAConstCmp { /// Wraps `reference` in a `CmpWrapper`. #[inline(always)] pub const fn coerce(self, reference: &str) -> CmpWrapper<&str> { CmpWrapper(reference) } } impl IsAConstCmp { /// Wraps `reference` in a `CmpWrapper`. #[inline(always)] pub const fn coerce(self, reference: &[T]) -> CmpWrapper<&[T]> { CmpWrapper(reference) } } impl IsAConstCmp { /// Wraps `reference` in a `CmpWrapper`. #[inline(always)] pub const fn coerce(self, reference: &[T; N]) -> CmpWrapper<&[T]> { CmpWrapper(reference) } } konst-0.3.16/src/cmp.rs000064400000000000000000000006621046102023000127710ustar 00000000000000//! Comparisong-related items. mod cmp_wrapper; mod const_cmp; pub use self::{ cmp_wrapper::CmpWrapper, const_cmp::{ConstCmp, ConstCmpUnref, IsAConstCmp}, }; #[doc(no_inline)] pub use crate::polymorphism::kinds::{IsNotStdKind, IsRefKind, IsStdKind}; #[doc(no_inline)] pub use crate::{ coerce_to_cmp, const_cmp, const_cmp_for, const_eq, const_eq_for, impl_cmp, max, max_by, max_by_key, min, min_by, min_by_key, }; konst-0.3.16/src/docs.rs000064400000000000000000000001351046102023000131350ustar 00000000000000//! Documentation for concepts not specific to any one item //! //! pub mod type_witnesses; konst-0.3.16/src/ffi/cstr/err_tests.rs000064400000000000000000000022631046102023000157420ustar 00000000000000// Tests errors from the cstr module, which can't be tested in the // top-level tests folder. use crate::ffi::cstr; #[test] fn from_bytes_until_nul_errs_test() { { let cs = cstr::from_bytes_until_nul(b"hello\0world").unwrap(); assert_eq!(cs.to_str().unwrap(), "hello"); } let _ = cstr::from_bytes_until_nul(b"helloworld").unwrap_err(); let _ = cstr::from_bytes_until_nul(b"").unwrap_err(); } #[test] fn from_bytes_with_nul_errs_test() { { let cs = cstr::from_bytes_with_nul(b"hello\0").unwrap(); assert_eq!(cs.to_str().unwrap(), "hello"); } for string in [&b""[..], &b"hello\0aaa"[..]] { let err = cstr::from_bytes_with_nul(string).unwrap_err(); assert!( matches!(err.kind, cstr::HuntNulError::NotNulTerminated), "{err:?} {string:?}", ); } for (string, pos) in [ (&b"\0helloaaa\0"[..], 0), (&b"h\0elloaaa\0"[..], 1), (b"hello\0aaa\0", 5), ] { let err = cstr::from_bytes_with_nul(string).unwrap_err(); assert_eq!( err.kind, cstr::HuntNulError::InternalNul(pos), "{err:?} {string:?}", ); } } konst-0.3.16/src/ffi/cstr.rs000064400000000000000000000166241046102023000137360ustar 00000000000000//! Const equivalents of [`CStr`] methods #[cfg(test)] mod err_tests; use crate::slice::slice_up_to; use core::{ffi::CStr, fmt}; //////////////////////////////////////////////////////////////////////////////// /// Error returned by [`from_bytes_until_nul`] when the input slice either /// does not terminate with nul. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromBytesUntilNulError(()); impl FromBytesUntilNulError { /// Const equivalent of `FromBytesUntilNulError::clone` pub const fn copy(&self) -> Self { Self(()) } /// Panics with this type's error message #[track_caller] pub const fn panic(&self) -> ! { panic!("{}", self.err_msg()) } const fn err_msg(&self) -> &str { "data provided does not contain a nul" } } impl fmt::Display for FromBytesUntilNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.err_msg()) } } //////////////////////////////////////////////////////////////////////////////// /// Error returned by [`from_bytes_with_nul`] when the input slice either /// does not terminate with nul, or contains inner nul bytes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromBytesWithNulError { kind: HuntNulError, } impl FromBytesWithNulError { /// Const equivalent of `FromBytesWithNulError::clone` pub const fn copy(&self) -> Self { Self { kind: self.kind } } const fn err_msg(&self) -> (&str, Option) { match self.kind { HuntNulError::InternalNul(pos) => { ("input bytes contain an internal nul byte at: ", Some(pos)) } HuntNulError::NotNulTerminated => ("input bytes don't terminate with nul", None), } } /// Panics with this type's error message #[track_caller] pub const fn panic(&self) -> ! { use const_panic::{concat_panic, FmtArg, PanicVal}; let (msg, num) = self.err_msg(); concat_panic(&[&[ PanicVal::write_str(msg), match num { Some(x) => PanicVal::from_usize(x, FmtArg::DEBUG), None => PanicVal::EMPTY, }, ]]) } } impl fmt::Display for FromBytesWithNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (msg, num) = self.err_msg(); f.write_str(msg)?; if let Some(num) = num { write!(f, "{num}")?; } Ok(()) } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum HuntNulError { InternalNul(usize), NotNulTerminated, } //////////////////////////////////////////////////////////////////////////////// struct CStrAndLen<'a> { cstr: &'a CStr, length_with_nul: usize, } const fn from_bytes_until_nul_inner( bytes: &[u8], ) -> Result, FromBytesUntilNulError> { crate::for_range! {i in 0..bytes.len() => if bytes[i] == 0 { let sub = slice_up_to(bytes, i + 1); unsafe { return Ok(CStrAndLen{ cstr: CStr::from_bytes_with_nul_unchecked(sub), length_with_nul: i + 1, }); } } } Err(FromBytesUntilNulError(())) } /// Converts a byte slice which contains any amount of nul bytes into a `&CStr`. /// Const equivalent of [`CStr::from_bytes_until_nul`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.69.0. /// /// # Example /// /// ```rust /// use konst::{ffi::cstr, unwrap_ctx}; /// /// use std::ffi::CStr; /// /// /// const CS: &CStr = unwrap_ctx!(cstr::from_bytes_until_nul(b"hello\0world")); /// /// assert_eq!(CS.to_str().unwrap(), "hello"); /// /// ``` /// pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { match from_bytes_until_nul_inner(bytes) { Ok(CStrAndLen { cstr, .. }) => Ok(cstr), Err(e) => Err(e), } } /// Converts a nul-terminated byte slice into a `&CStr`. /// Const equivalent of [`CStr::from_bytes_with_nul`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.72.0. /// /// # Example /// /// ```rust /// use konst::{ffi::cstr, unwrap_ctx}; /// /// use std::ffi::CStr; /// /// /// const CS: &CStr = unwrap_ctx!(cstr::from_bytes_with_nul(b"foo bar\0")); /// /// assert_eq!(CS.to_str().unwrap(), "foo bar"); /// /// ``` /// pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { const fn make_not_null_term_err() -> Result { Err(FromBytesWithNulError { kind: HuntNulError::NotNulTerminated, }) } match from_bytes_until_nul_inner(bytes) { Ok(CStrAndLen { cstr, length_with_nul, }) if length_with_nul == bytes.len() => Ok(cstr), Ok(_) if bytes[bytes.len() - 1] != 0 => make_not_null_term_err(), Err(_) => make_not_null_term_err(), Ok(CStrAndLen { length_with_nul, .. }) => Err(FromBytesWithNulError { kind: HuntNulError::InternalNul(length_with_nul - 1), }), } } /// Converts this CStr to a byte slice, including the nul terminator. /// Const equivalent of [`CStr::to_bytes_with_nul`] /// /// # Performance /// /// This function takes linear time to run, proportional to the length of `this`. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.72.0. /// /// # Example /// /// ```rust /// use konst::{ffi::cstr, unwrap_ctx}; /// /// use std::ffi::CStr; /// /// /// const CS: &CStr = unwrap_ctx!(cstr::from_bytes_with_nul(b"example\0")); /// /// const BYTES: &[u8] = cstr::to_bytes_with_nul(CS); /// /// assert_eq!(BYTES, b"example\0"); /// /// ``` pub const fn to_bytes_with_nul(this: &CStr) -> &[u8] { let start = this.as_ptr().cast::(); let mut i = 0; unsafe { while *start.add(i) != 0 { i += 1; } core::slice::from_raw_parts(start, i + 1) } } /// Converts this CStr to a byte slice, excluding the nul terminator. /// Const equivalent of [`CStr::to_bytes`] /// /// # Performance /// /// This function takes linear time to run, proportional to the length of `this`. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.72.0. /// /// # Example /// /// ```rust /// use konst::{ffi::cstr, unwrap_ctx}; /// /// use std::ffi::CStr; /// /// /// const CS: &CStr = unwrap_ctx!(cstr::from_bytes_with_nul(b"hmm...\0")); /// /// const BYTES: &[u8] = cstr::to_bytes(CS); /// /// assert_eq!(BYTES, b"hmm..."); /// /// ``` pub const fn to_bytes(this: &CStr) -> &[u8] { match to_bytes_with_nul(this) { [rem @ .., 0] => rem, _ => unreachable!(), } } /// Converts this CStr to a string slice, excluding the nul terminator. /// Const equivalent of [`CStr::to_str`] /// /// # Performance /// /// This function takes linear time to run, proportional to the length of `this`. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.72.0. /// /// # Example /// /// ```rust /// use konst::{ffi::cstr, unwrap_ctx}; /// /// use std::ffi::CStr; /// /// /// const CS: &CStr = unwrap_ctx!(cstr::from_bytes_with_nul(b"of beads\0")); /// /// const STRING: &str = unwrap_ctx!(cstr::to_str(CS)); /// /// assert_eq!(STRING, "of beads"); /// /// ``` pub const fn to_str(this: &CStr) -> Result<&str, crate::string::Utf8Error> { crate::string::from_utf8(to_bytes(this)) } konst-0.3.16/src/ffi.rs000064400000000000000000000000161046102023000127470ustar 00000000000000pub mod cstr; konst-0.3.16/src/iter/collect_const.rs000064400000000000000000000033061046102023000160060ustar 00000000000000/** Collects an iterator constant into an array # Iterator methods This macro supports emulating iterator methods by expanding to equivalent code. The supported iterator methods are documented in the [`iterator_dsl`] module, because they are also supported by other `konst::iter` macros. # Syntax The syntax of this macro is: ```text collect_const!( $Item:ty => $into_iterator:expr $(, $iterator_method:ident ($($method_args:tt)*) )* $(,)? ) ``` Where `$Item` is the type of the elements that'll be collected into an array. Where `$into_iterator` is any type that can be converted into a const iterator, with [`konst::iter::into_iter`](crate::iter::into_iter). Where `$iterator_method` is any of the supported methods described in the [`iterator_dsl`] module. # Examples ### Iterating over a range ```rust use konst::iter; const ARR: [u64; 8] = iter::collect_const!(u64 => 10.., filter(|n| *n % 2 == 0), skip(5), take(8), ); assert_eq!(ARR, [20, 22, 24, 26, 28, 30, 32, 34]); ``` ### Iterating over an array ```rust use konst::iter; const ARR: [u8; 6] = iter::collect_const!(u8 => // the `&` is required here, // because by-value iteration over arrays is not supported. &[10, 20, 30], flat_map(|&n| { // To allow returning references to arrays, the macro extends // the lifetime of borrows to temporaries in return position. // The lifetime of the array is extended to the entire iterator chain. &[n - 1, n + 1] }), copied() ); assert_eq!(ARR, [9, 11, 19, 21, 29, 31]); ``` [`iterator_dsl`]: crate::iter::iterator_dsl */ pub use konst_kernel::iter_collect_const as collect_const;konst-0.3.16/src/iter/iter_eval.rs000064400000000000000000000162211046102023000151250ustar 00000000000000/** Emulates iterator method chains, by expanding to equivalent code. For examples that use multiple methods [look here](#full-examples) # Methods ### Consuming methods Consuming methods are those that consume the iterator, returning a non-iterator. The consuming methods listed alphabetically: - [`all`](#all) - [`any`](#any) - [`count`](#count) - [`find_map`](#find_map) - [`find`](#find) - [`fold`](#fold) - [`for_each`](#for_each) - [`next`](#next) - [`nth`](#nth) - [`position`](#position) - [`rfind`](#rfind) - [`rfold`](#rfold) - [`rposition`](#rposition) ### Adaptor Methods Adaptor methods are those that transform the iterator into a different iterator. They are shared with other `konst::iter` macros and are documented in the [`iterator_dsl`] module. The iterator adaptor methods, listed alphabetically (these links go to the [`iterator_dsl`] module): - [`copied`](./iterator_dsl/index.html#copied) - [`enumerate`](./iterator_dsl/index.html#enumerate) - [`filter_map`](./iterator_dsl/index.html#filter_map) - [`filter`](./iterator_dsl/index.html#filter) - [`flat_map`](./iterator_dsl/index.html#flat_map) - [`flatten`](./iterator_dsl/index.html#flatten) - [`map`](./iterator_dsl/index.html#map) - [`rev`](./iterator_dsl/index.html#rev) - [`skip_while`](./iterator_dsl/index.html#skip_while) - [`skip`](./iterator_dsl/index.html#skip) - [`take_while`](./iterator_dsl/index.html#take_while) - [`take`](./iterator_dsl/index.html#take) - [`zip`](./iterator_dsl/index.html#zip) ### `all` Const equivalent of [`Iterator::all`] ```rust use konst::iter; const fn all_digits(s: &str) -> bool { iter::eval!(s.as_bytes(),all(|c| matches!(c, b'0'..=b'9'))) } assert!(all_digits("123456")); assert!(!all_digits("0x123456")); ``` ### `any` Const equivalent of [`Iterator::any`] ```rust use konst::iter; const fn contains_pow2(s: &[u64]) -> bool { iter::eval!(s,any(|c| c.is_power_of_two())) } assert!(contains_pow2(&[2, 3, 5])); assert!(!contains_pow2(&[13, 21, 34])); ``` ### `count` Const equivalent of [`Iterator::count`] ```rust use konst::{iter, string}; const fn count_csv(s: &str) -> usize { iter::eval!(string::split(s, ","),count()) } assert_eq!(count_csv("foo"), 1); assert_eq!(count_csv("foo,bar"), 2); assert_eq!(count_csv("foo,bar,baz"), 3); ``` ### `for_each` Alternative way to write [`konst::iter::for_each`](crate::iter::for_each) ```rust use konst::iter; const fn sum_elems(s: &[u64]) -> u64 { let mut sum = 0u64; iter::eval!{s,copied(),for_each(|x| sum+=x)} sum } assert_eq!(sum_elems(&[]), 0); assert_eq!(sum_elems(&[2]), 2); assert_eq!(sum_elems(&[3, 5]), 8); ``` ### `next` Gets the first element in the iterator, only needed when intermediate Iterator methods are used. ```rust use konst::iter; const fn first_elem(s: &[u64]) -> Option { iter::eval!(s,copied(),next()) } assert_eq!(first_elem(&[]), None); assert_eq!(first_elem(&[2]), Some(2)); assert_eq!(first_elem(&[3, 5]), Some(3)); ``` ### `nth` Const equivalent of [`Iterator::nth`] ```rust use konst::{iter, string}; const fn nth_csv(s: &str, nth: usize) -> Option<&str> { iter::eval!(string::split(s, ","),nth(nth)) } assert_eq!(nth_csv("foo,bar,baz", 0), Some("foo")); assert_eq!(nth_csv("foo,bar,baz", 1), Some("bar")); assert_eq!(nth_csv("foo,bar,baz", 2), Some("baz")); assert_eq!(nth_csv("foo,bar,baz", 3), None); ``` ### `position` Const equivalent of [`Iterator::position`] ```rust use konst::iter; const fn find_num(slice: &[u64], n: u64) -> Option { iter::eval!(slice,position(|&elem| elem == n)) } assert_eq!(find_num(&[3, 5, 8], 0), None); assert_eq!(find_num(&[3, 5, 8], 3), Some(0)); assert_eq!(find_num(&[3, 5, 8], 5), Some(1)); assert_eq!(find_num(&[3, 5, 8], 8), Some(2)); ``` ### `rposition` Const equivalent of [`Iterator::rposition`] Limitation: iterator-reversing methods can't be called more than once in the same macro invocation. ```rust use konst::iter; const fn rfind_num(slice: &[u64], n: u64) -> Option { iter::eval!(slice,rposition(|&elem| elem == n)) } assert_eq!(rfind_num(&[3, 5, 8], 0), None); assert_eq!(rfind_num(&[3, 5, 8], 3), Some(2)); assert_eq!(rfind_num(&[3, 5, 8], 5), Some(1)); assert_eq!(rfind_num(&[3, 5, 8], 8), Some(0)); ``` ### `find` Const equivalent of [`Iterator::find`] ```rust use konst::iter; const fn find_odd(slice: &[u64], n: u64) -> Option<&u64> { iter::eval!(slice,find(|&&elem| elem % 2 == 1)) } assert_eq!(find_odd(&[], 0), None); assert_eq!(find_odd(&[2, 4], 0), None); assert_eq!(find_odd(&[3, 5, 8], 3), Some(&3)); assert_eq!(find_odd(&[8, 12, 13], 3), Some(&13)); ``` ### `find_map` Const equivalent of [`Iterator::find_map`] This example requires the `"parsing"` feature. */ #[cfg_attr(not(feature = "parsing"), doc = "```ignore")] #[cfg_attr(feature = "parsing", doc = "```rust")] /** use konst::{iter, result}; use konst::primitive::parse_u64; const fn find_parsable(slice: &[&str]) -> Option { iter::eval!(slice,find_map(|&s| result::ok!(parse_u64(s)))) } assert_eq!(find_parsable(&[]), None); assert_eq!(find_parsable(&["foo"]), None); assert_eq!(find_parsable(&["foo", "10"]), Some(10)); assert_eq!(find_parsable(&["10", "20"]), Some(10)); ``` ### `rfind` Const equivalent of [`DoubleEndedIterator::rfind`] Limitation: iterator-reversing methods can't be called more than once in the same macro invocation. ```rust use konst::iter; const fn sum_u64(slice: &[u64]) -> Option<&u64> { iter::eval!(slice,rfind(|&elem| elem.is_power_of_two())) } assert_eq!(sum_u64(&[]), None); assert_eq!(sum_u64(&[2]), Some(&2)); assert_eq!(sum_u64(&[2, 5, 8]), Some(&8)); ``` ### `fold` Const equivalent of [`Iterator::fold`] ```rust use konst::iter; const fn sum_u64(slice: &[u64]) -> u64 { iter::eval!(slice,fold(0, |accum, &rhs| accum + rhs)) } assert_eq!(sum_u64(&[]), 0); assert_eq!(sum_u64(&[3]), 3); assert_eq!(sum_u64(&[3, 5]), 8); assert_eq!(sum_u64(&[3, 5, 8]), 16); ``` ### `rfold` Const equivalent of [`DoubleEndedIterator::rfold`] Limitation: iterator-reversing methods can't be called more than once in the same macro invocation. ```rust use konst::iter; const fn concat_u16s(slice: &[u16]) -> u128 { iter::eval!(slice,rfold(0, |accum, &rhs| (accum << 16) + (rhs as u128))) } assert_eq!(concat_u16s(&[1, 2, 3]), 0x0003_0002_0001); assert_eq!(concat_u16s(&[3, 5, 8]), 0x0008_0005_0003); ``` # Examples ### Second number in CSV This example demonstrates a function that gets the second number in a CSV string, using iterators. This example requires the `"parsing"` feature. */ #[cfg_attr(not(feature = "parsing"), doc = "```ignore")] #[cfg_attr(feature = "parsing", doc = "```rust")] /** use konst::{ iter, primitive::parse_u64, result, string, }; const fn second_number(s: &str) -> Option { iter::eval!( string::split(s, ","), filter_map(|s| result::ok!(parse_u64(s))), nth(1), ) } assert_eq!(second_number("foo,bar,baz"), None); assert_eq!(second_number("foo,3,bar"), None); assert_eq!(second_number("foo,3,bar,5"), Some(5)); assert_eq!(second_number("foo,8,bar,13,baz,21"), Some(13)); ``` [`iterator_dsl`]: ./iterator_dsl/index.html */ pub use konst_kernel::iter_eval as eval;konst-0.3.16/src/iter/iterator_adaptors.rs000064400000000000000000000010311046102023000166720ustar 00000000000000/// Const analog of [`core::iter::repeat`], /// except that this requires the repeated value to impl `Copy` /// (instead of `Clone`). /// /// # Example /// /// ```rust /// use konst::iter::{self, collect_const}; /// /// const ARR: &[u8] = &collect_const!(u8 => iter::repeat(3),take(5)); /// /// assert_eq!(ARR, &[3, 3, 3, 3, 3]); /// ``` pub use konst_kernel::iter::iter_adaptors::repeat; /// Const analog of [`core::iter::Repeat`], /// constructed by [`repeat`](crate::iter::repeat). pub use konst_kernel::iter::iter_adaptors::Repeat; konst-0.3.16/src/iter/iterator_dsl.rs000064400000000000000000000071071046102023000156510ustar 00000000000000/*! Documentation on the iterator DSL that some `konst::iter` macros support. The macros from this crate don't directly invoke any of the method listed below, they expand to equivalent code, this allows the macros to work on stable. The [`collect_const`](crate::iter::collect_const) macro is used in examples here purely for simplicity. # Methods Every iterator method below behaves the same as in the [`Iterator`] trait, unless specified otherwise. The methods listed alphabetically: - [`copied`](#copied) - [`enumerate`](#enumerate) - [`filter_map`](#filter_map) - [`filter`](#filter) - [`flat_map`](#flat_map) - [`flatten`](#flatten) - [`map`](#map) - [`rev`](#rev) - [`skip_while`](#skip_while) - [`skip`](#skip) - [`take_while`](#take_while) - [`take`](#take) - [`zip`](#zip) ### `zip` Limitation: the iterator DSL can't be passed as an argument to this method. ```rust use konst::iter; const ARR: [(&u8, usize); 4] = iter::collect_const!((&u8, usize) => &[3u8, 5, 8, 13],zip(100..)); assert_eq!(ARR, [(&3, 100), (&5, 101), (&8, 102), (&13, 103)]); ``` ### `enumerate` `enumerate` always counts from `0`, regardless of whether the iterator is reversed. ```rust use konst::iter; const ARR: [(usize, &u8); 4] = iter::collect_const!((usize, &u8) => &[3u8, 5, 8, 13],enumerate()); assert_eq!(ARR, [(0, &3), (1, &5), (2, &8), (3, &13)]); ``` ### `filter` ```rust use konst::iter; const ARR: [&u8; 4] = iter::collect_const!(&u8 => &[3u8, 5, 8, 13, 21], filter(|e| !e.is_power_of_two()), ); assert_eq!(ARR, [&3, &5, &13, &21]); ``` ### `map` ```rust use konst::iter; const ARR: [usize; 4] = iter::collect_const!(usize => (1..=4),map(|e| e * 3)); assert_eq!(ARR, [3, 6, 9, 12]); ``` ### `filter_map` ```rust use konst::iter; use std::num::NonZeroU8; const ARR: [NonZeroU8; 4] = iter::collect_const!(NonZeroU8 => &[3, 0, 1, 5, 6], filter_map(|x| NonZeroU8::new(*x)), ); assert_eq!(ARR, [3, 1, 5, 6].map(|n| NonZeroU8::new(n).unwrap())); ``` ### `flat_map` Limitation: the iterator DSL can't be passed as an argument to this method. ```rust use konst::iter; const ARR: [usize; 9] = iter::collect_const!(usize => &[3, 5, 8], flat_map(|x| { let x10 = *x * 10; x10..x10 + 3 }), ); assert_eq!(ARR, [30, 31, 32, 50, 51, 52, 80, 81, 82]); ``` ### `flatten` ```rust use konst::iter; const ARR: [&u8; 4] = iter::collect_const!(&u8 => &[&[3, 5], &[8, 13]], flatten()); assert_eq!(ARR, [&3, &5, &8, &13]); ``` ### `copied` ```rust use konst::iter; const ARR: [u8; 3] = iter::collect_const!(u8 => &[2, 3, 4, 5, 6], copied(), filter(|n| *n % 2 == 0) ); assert_eq!(ARR, [2, 4, 6]); ``` ### `rev` Limitation: iterator-reversing methods can't be called more than once in the same macro invocation. ```rust use konst::iter; const ARR: [&u8; 3] = iter::collect_const!(&u8 => &[2, 3, 5],rev()); assert_eq!(ARR, [&5, &3, &2]); ``` ### `take` ```rust use konst::iter; const ARR: [usize; 3] = iter::collect_const!(usize => 10..,take(3)); assert_eq!(ARR, [10, 11, 12]); ``` ### `take_while` ```rust use konst::iter; const ARR: [&u8; 4] = iter::collect_const!(&u8 => &[3, 5, 8, 13, 21, 34, 55],take_while(|elem| **elem < 20 ) ); assert_eq!(ARR, [&3, &5, &8, &13]); ``` ### `skip` ```rust use konst::iter; const ARR: [usize; 3] = iter::collect_const!(usize => 10..=15,skip(3)); assert_eq!(ARR, [13, 14, 15]); ``` ### `skip_while` ```rust use konst::iter; const ARR: [&u8; 3] = iter::collect_const!(&u8 => &[3, 5, 8, 13, 21, 34, 55],skip_while(|elem| **elem < 20 ) ); assert_eq!(ARR, [&21, &34, &55]); ``` */ konst-0.3.16/src/iter.rs000064400000000000000000000302061046102023000131520ustar 00000000000000//! Const equivalent of iterators with a specific `next` function signature. //! //! The docs for [`ConstIntoIter`] has more information on //! const equivalents of IntoIterator and Iterator. //! mod iterator_adaptors; pub mod iterator_dsl; pub use iterator_adaptors::*; /// Iterates over all elements of an [iterator](crate::iter::ConstIntoIter), /// const equivalent of [`Iterator::for_each`] /// /// # Syntax /// /// ```text /// for_each!{ /// $pattern:pat in $iterator:expr /// $(,$iterator_method:ident ($($method_args:tt)*) )* /// $(,)? /// => /// $($code:tt)* /// } /// ``` /// /// This macro supports emulating iterator methods by expanding to equivalent code. /// They are documented in the [`iterator_dsl`] module, /// because they are also supported by other `konst::iter` macros. /// /// # Examples /// /// ### Custom iterator /// /// ```rust /// use konst::iter::{ConstIntoIter, IsIteratorKind}; /// /// struct Upto10(u8); /// /// impl ConstIntoIter for Upto10 { /// type Kind = IsIteratorKind; /// type IntoIter = Self; /// type Item = u8; /// } /// /// impl Upto10 { /// const fn next(mut self) -> Option<(u8, Self)> { /// if self.0 < 10 { /// let ret = self.0; /// self.0 += 1; /// Some((ret, self)) /// } else { /// None /// } /// } /// } /// /// const N: u32 = { /// let mut n = 0u32; /// konst::iter::for_each!{elem in Upto10(7) => /// n = n * 10 + elem as u32; /// } /// n /// }; /// /// assert_eq!(N, 789); /// /// ``` /// /// ### Summing pairs /// /// ```rust /// use konst::iter::for_each; /// /// const fn add_pairs(l: [u32; N], r: [u32; N]) -> [u32; N] { /// let mut out = [0u32; N]; /// /// for_each!{(i, val) in &l,zip(&r),map(|(l, r)| *l + *r),enumerate() => /// out[i] = val; /// } /// /// out /// } /// /// assert_eq!(add_pairs([], []), []); /// assert_eq!(add_pairs([3], [5]), [8]); /// assert_eq!(add_pairs([3, 5], [8, 13]), [11, 18]); /// /// ``` /// /// [`iterator_dsl`]: crate::iter::iterator_dsl pub use konst_kernel::for_each; /// Wrapper for `ConstIntoIter` implementors, /// that defines different methods depending on the /// value of `K`. #[doc(inline)] pub use konst_kernel::into_iter::IntoIterWrapper; /// Marker type for proving that `T: ConstIntoIter` #[doc(inline)] pub use konst_kernel::into_iter::IsConstIntoIter; /// Macro for converting [`ConstIntoIter`] implementors into const iterators. /// /// # Behavior /// /// For std types (`ConstIntoIter`), /// this converts those types to their iterator. /// [(example below)](#std-type-example) /// /// For user-defined into-iterators (`ConstIntoIter`), /// this calls their `const_into_iter` inherent method to convert them to an iterator. /// [(example below)](#into-iter-example) /// /// For iterators (`ConstIntoIter`), /// this returns the iterator untouched. /// [(example below)](#iterator-example) /// /// # Examples /// /// /// ### Std type /// /// This example demonstrates passing a `ConstIntoIter` in. /// /// ```rust /// use konst::{iter, slice}; /// /// let mut elem; /// let mut iter: slice::Iter<'_, u8> = iter::into_iter!(&[3, 5, 8]); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, &3); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, &5); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, &8); /// /// assert!(iter.next().is_none()); /// /// ``` /// /// /// ### IntoIterator type /// /// This example demonstrates passing a `ConstIntoIter` in. /// /// ```rust /// use konst::{iter, string}; /// /// let mut iter: Countdown = iter::into_iter!(Number(3)); /// let mut elem; /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, 2); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, 1); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, 0); /// /// assert!(iter.next().is_none()); /// /// /// struct Number(u32); /// /// impl iter::ConstIntoIter for Number { /// type Kind = iter::IsIntoIterKind; /// type Item = u32; /// type IntoIter = Countdown; /// } /// /// impl Number { /// const fn const_into_iter(self) -> Countdown { /// Countdown(self.0) /// } /// } /// /// struct Countdown(u32); /// /// impl iter::ConstIntoIter for Countdown { /// type Kind = iter::IsIteratorKind; /// type Item = u32; /// type IntoIter = Self; /// } /// /// impl Countdown { /// const fn next(self) -> Option<(u32, Self)> { /// let next = konst::try_opt!(self.0.checked_sub(1)); /// Some((next, Countdown(next))) /// } /// } /// /// /// ``` /// /// /// ### Iterator type /// /// This example demonstrates passing a `ConstIntoIter` in. /// /// ```rust /// use konst::{iter, string}; /// /// let iter: string::Split<'_, '_, char> = string::split("foo bar baz", ' '); /// /// // `iter::into_iter` is an identity function when passed iterators /// let mut iter: string::Split<'_, '_, char> = iter::into_iter!(iter); /// let mut elem; /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "foo"); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "bar"); /// /// (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "baz"); /// /// assert!(iter.next().is_none()); /// ``` /// /// #[doc(inline)] pub use konst_kernel::into_iter_macro as into_iter; /// Const analog of the [`IntoIterator`] trait. /// /// # Implementor /// /// Implementors are expected to be one of these: /// /// - [`IsIntoIterKind` kind](#isintoiterkind) /// - [`IsIteratorKind` kind](#isiteratorkind) /// - Standard library types, of the [`IsStdKind`] kind /// /// ### `IsIntoIterKind` /// /// These are user-defined types convertible to const iterators. /// /// These implement `ConstIntoIter` /// and are expected to define this inherent method for converting to /// a const iterator: /// /// ```rust /// # struct II; /// # struct SomeIterator; /// # impl II { /// const fn const_into_iter(self) -> SomeIterator { /// # loop{} /// # } /// # } /// ``` /// /// [full example below](#non-iter-example) /// /// ### `IsIteratorKind` /// /// These are const iterator types. /// /// These implement `ConstIntoIter` /// and are expected to define this inherent method: /// /// ```rust /// # struct SomeIterator; /// # type Item = u8; /// # impl SomeIterator { /// // Equivalent to `Iterator::next` /// const fn next(self) -> Option<(Item, Self)> { /// # loop{} /// # } /// # } /// ``` /// Where `Item` can be any type. /// /// These are other methods that you can optionaly define, /// which most iterators from the `konst` crate define: /// ```rust /// # struct SomeIterator; /// # struct SomeIteratorRev; /// # type Item = u8; /// # impl SomeIterator { /// // equivalent to `DoubleEndedÌterator::mext_back` /// const fn next_back(self) -> Option<(Item, Self)> { /// # loop{} /// // ... some code... /// } /// /// // Reverses the iterator, equivalent to `Iterator::rev` /// const fn rev(self) -> SomeIteratorRev { /// # loop{} /// // ... some code... /// } /// /// // Clones the iterator, equivalent to `Clone::clone` /// const fn copy(&self) -> Self { /// # loop{} /// // ... some code... /// } /// # } /// ``` /// Where `SomeIteratorRev` should be a `ConstIntoIter` /// which has the same inherent methods for iteration, /// and returns the same `Item` type. /// /// [full example below](#iter-example) /// /// # Examples /// /// /// ### Implementing for an into-iterator /// /// ```rust /// use konst::{iter, slice}; /// /// struct GetSlice<'a, T>{ /// slice: &'a [T], /// up_to: usize, /// } /// /// impl<'a, T> iter::ConstIntoIter for GetSlice<'a, T> { /// type Kind = iter::IsIntoIterKind; /// type IntoIter = konst::slice::Iter<'a, T>; /// type Item = &'a T; /// } /// /// impl<'a, T> GetSlice<'a, T> { /// const fn const_into_iter(self) -> konst::slice::Iter<'a, T> { /// slice::iter(slice::slice_up_to(self.slice, self.up_to)) /// } /// } /// /// const fn sum_powers(up_to: usize) -> u64 { /// let gs = GetSlice{slice: &[1, 2, 4, 8, 16, 32, 64, 128], up_to}; /// /// iter::eval!(gs,fold(0, |l, &r| l + r)) /// } /// /// assert_eq!(sum_powers(0), 0); /// assert_eq!(sum_powers(1), 1); /// assert_eq!(sum_powers(2), 3); /// assert_eq!(sum_powers(3), 7); /// assert_eq!(sum_powers(4), 15); /// assert_eq!(sum_powers(5), 31); /// /// ``` /// /// /// ### Implementing for an iterator /// /// ```rust /// use konst::iter::{self, ConstIntoIter}; /// /// struct Countdown(u8); /// /// impl ConstIntoIter for Countdown { /// type Kind = iter::IsIteratorKind; /// type IntoIter = Self; /// type Item = u8; /// } /// /// impl Countdown { /// const fn next(mut self) -> Option<(u8, Self)> { /// konst::option::map!(self.0.checked_sub(1), |ret| { /// self.0 = ret; /// (ret, self) /// }) /// } /// } /// /// const fn sum(initial: u8) -> u16 { /// iter::eval!(Countdown(initial),fold(0u16, |accum, elem| accum + elem as u16)) /// } /// /// assert_eq!(sum(0), 0); /// assert_eq!(sum(1), 0); /// assert_eq!(sum(2), 1); /// assert_eq!(sum(3), 3); /// assert_eq!(sum(4), 6); /// assert_eq!(sum(5), 10); /// /// ``` /// /// ### Implementing for a double-ended iterator /// /// ```rust /// use konst::iter; /// /// assert_eq!(HOURS, [1, 2, 3, 4, 5, 6, 12, 11, 10, 9, 8, 7]); /// /// const HOURS: [u8; 12] = { /// let mut arr = [0; 12]; /// let hours = Hours::new(); /// /// iter::for_each!{(i, hour) in 0..6,zip(hours.copy()) => /// arr[i] = hour; /// } /// iter::for_each!{(i, hour) in 6..12,zip(hours.rev()) => /// arr[i] = hour; /// } /// /// arr /// }; /// /// /// struct Hours{ /// start: u8, /// end: u8, /// } /// /// impl iter::ConstIntoIter for Hours { /// type Kind = iter::IsIteratorKind; /// type IntoIter = Self; /// type Item = u8; /// } /// /// impl Hours { /// const fn new() -> Self { /// Self {start: 1, end: 13} /// } /// /// const fn next(mut self) -> Option<(u8, Self)> { /// if self.start == self.end { /// None /// } else { /// let ret = self.start; /// self.start += 1; /// Some((ret, self)) /// } /// } /// /// const fn next_back(mut self) -> Option<(u8, Self)> { /// if self.start == self.end { /// None /// } else { /// self.end -= 1; /// Some((self.end, self)) /// } /// } /// /// const fn rev(self) -> HoursRev { /// HoursRev(self) /// } /// /// /// Since `Clone::clone` isn't const callable on stable, /// /// clonable iterators must define an inherent method to be cloned /// const fn copy(&self) -> Self { /// let Self{start, end} = *self; /// Self{start, end} /// } /// } /// /// struct HoursRev(Hours); /// /// impl iter::ConstIntoIter for HoursRev { /// type Kind = iter::IsIteratorKind; /// type IntoIter = Self; /// type Item = u8; /// } /// /// impl HoursRev { /// const fn next(self) -> Option<(u8, Self)> { /// konst::option::map!(self.0.next_back(), |(a, h)| (a, HoursRev(h))) /// } /// /// const fn next_back(self) -> Option<(u8, Self)> { /// konst::option::map!(self.0.next(), |(a, h)| (a, HoursRev(h))) /// } /// /// const fn rev(self) -> Hours { /// self.0 /// } /// /// const fn copy(&self) -> Self { /// Self(self.0.copy()) /// } /// } /// /// /// ``` /// #[doc(inline)] pub use konst_kernel::into_iter::ConstIntoIter; #[doc(no_inline)] pub use crate::polymorphism::kinds::{IsIntoIterKind, IsIteratorKind, IsStdKind}; /// Trait for all the types that can be iterated over with ranges. /// /// This trait is sealed and can only be implemented by `konst` pub use konst_kernel::step_kk::Step; include! {"./iter/collect_const.rs"} include! {"./iter/iter_eval.rs"} konst-0.3.16/src/lib.rs000064400000000000000000000301551046102023000127600ustar 00000000000000//! Const equivalents of std functions and const parsing. //! //! # Features //! //! This crate provides: //! //! - Const fn equivalents of standard library functions and methods. //! //! - [`destructure`] macro to allow destructuring types in const without getting "cannot drop in const" errors. //! //! - Compile-time parsing through the [`Parser`] type, and [`parser_method`] macro. //! //! # Examples //! //! ### Parsing an enum //! //! This example demonstrates how you can parse a simple enum from an environment variable, //! at compile-time. //! //! ```rust //! use konst::{ //! eq_str, //! option, //! result::unwrap_ctx, //! }; //! //! #[derive(Debug, PartialEq)] //! enum Direction { //! Forward, //! Backward, //! Left, //! Right, //! } //! //! impl Direction { //! const fn try_parse(input: &str) -> Result { //! // As of Rust 1.65.0, string patterns don't work in const contexts //! match () { //! _ if eq_str(input, "forward") => Ok(Direction::Forward), //! _ if eq_str(input, "backward") => Ok(Direction::Backward), //! _ if eq_str(input, "left") => Ok(Direction::Left), //! _ if eq_str(input, "right") => Ok(Direction::Right), //! _ => Err(ParseDirectionError), //! } //! } //! } //! //! const CHOICE: &str = option::unwrap_or!(option_env!("chosen-direction"), "forward"); //! //! const DIRECTION: Direction = unwrap_ctx!(Direction::try_parse(CHOICE)); //! //! fn main() { //! match DIRECTION { //! Direction::Forward => assert_eq!(CHOICE, "forward"), //! Direction::Backward => assert_eq!(CHOICE, "backward"), //! Direction::Left => assert_eq!(CHOICE, "left"), //! Direction::Right => assert_eq!(CHOICE, "right"), //! } //! } //! //! #[derive(Debug, PartialEq)] //! pub struct ParseDirectionError; //! //! use std::fmt::{self, Display}; //! //! impl Display for ParseDirectionError { //! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { //! f.write_str("Failed to parse a Direction") //! } //! } //! //! impl ParseDirectionError { //! const fn panic(&self) -> ! { //! panic!("failed to parse a Direction") //! } //! } //! //! ``` //! //! ### Parsing CSV //! //! This example demonstrates how CSV can be parsed into integers. //! //! This example requires the `"parsing"` and `"iter"` features //! (both are enabled by default). //! #![cfg_attr(all(feature = "parsing", feature = "iter"), doc = "```rust")] #![cfg_attr(not(all(feature = "parsing", feature = "iter")), doc = "```ignore")] //! use konst::{ //! primitive::parse_u64, //! result::unwrap_ctx, //! iter, string, //! }; //! //! const CSV: &str = "3, 8, 13, 21, 34"; //! //! static PARSED: [u64; 5] = iter::collect_const!(u64 => //! string::split(CSV, ","), //! map(string::trim), //! map(|s| unwrap_ctx!(parse_u64(s))), //! ); //! //! assert_eq!(PARSED, [3, 8, 13, 21, 34]); //! //! ``` //! //! ### Parsing a struct //! //! This example demonstrates how a key-value pair format can be parsed into a struct. //! //! This requires the `"parsing_proc"` feature (enabled by default). //! #![cfg_attr(feature = "parsing_proc", doc = "```rust")] #![cfg_attr(not(feature = "parsing_proc"), doc = "```ignore")] //! use konst::{ //! parsing::{Parser, ParseValueResult}, //! eq_str, //! for_range, parser_method, try_, unwrap_ctx, //! }; //! //! const PARSED: Struct = { //! // You can also parse strings from environment variables, or from an `include_str!(....)` //! let input = "\ //! colors = red, blue, green, blue //! amount = 1000 //! repeating = circle //! name = bob smith //! "; //! //! unwrap_ctx!(parse_struct(Parser::new(input))).0 //! }; //! //! fn main(){ //! assert_eq!( //! PARSED, //! Struct{ //! name: "bob smith", //! amount: 1000, //! repeating: Shape::Circle, //! colors: [Color::Red, Color::Blue, Color::Green, Color::Blue], //! } //! ); //! } //! //! #[derive(Debug, Clone, PartialEq, Eq)] //! pub struct Struct<'a> { //! pub name: &'a str, //! pub amount: usize, //! pub repeating: Shape, //! pub colors: [Color; 4], //! } //! //! #[derive(Debug, Clone, PartialEq, Eq)] //! pub enum Shape { //! Circle, //! Square, //! Line, //! } //! //! #[derive(Debug, Copy, Clone, PartialEq, Eq)] //! pub enum Color { //! Red, //! Blue, //! Green, //! } //! //! pub const fn parse_struct(mut parser: Parser<'_>) -> ParseValueResult<'_, Struct<'_>> { //! let mut name = ""; //! let mut amount = 0; //! let mut repeating = Shape::Circle; //! let mut colors = [Color::Red; 4]; //! //! parser = parser.trim_end(); //! if !parser.is_empty() { //! loop { //! let mut prev_parser = parser.trim_start(); //! //! parser = try_!(parser.find_skip('=')); //! //! parser_method!{prev_parser, strip_prefix; //! "name" => (name, parser) = try_!(parser.trim_start().split_keep('\n')), //! "amount" => (amount, parser) = try_!(parser.trim_start().parse_usize()), //! "repeating" => (repeating, parser) = try_!(parse_shape(parser.trim_start())), //! "colors" => (colors, parser) = try_!(parse_colors(parser.trim_start())), //! _ => { //! let err = &"could not parse Struct field name"; //! return Err(prev_parser.into_other_error(err)); //! } //! } //! //! if parser.is_empty() { //! break //! } //! parser = try_!(parser.strip_prefix("\n")); //! } //! } //! //! Ok((Struct{name, amount, repeating, colors}, parser)) //! } //! //! pub const fn parse_shape(mut parser: Parser<'_>) -> ParseValueResult<'_, Shape> { //! let shape = parser_method!{parser, strip_prefix; //! "circle" => Shape::Circle, //! "square" => Shape::Square, //! "line" => Shape::Line, //! _ => return Err(parser.into_other_error(&"could not parse Shape")) //! }; //! Ok((shape, parser)) //! } //! //! pub const fn parse_colors( //! mut parser: Parser<'_>, //! ) -> ParseValueResult<'_, [Color; LEN]> { //! let mut colors = [Color::Red; LEN]; //! //! for_range!{i in 0..LEN => //! (colors[i], parser) = try_!(parse_color(parser.trim_start())); //! //! match parser.strip_prefix(",") { //! Ok(next) => parser = next, //! Err(_) if i == LEN - 1 => {} //! Err(e) => return Err(e), //! } //! } //! //! Ok((colors, parser)) //! } //! //! pub const fn parse_color(mut parser: Parser<'_>) -> ParseValueResult<'_, Color> { //! let color = parser_method!{parser, strip_prefix; //! "red" => Color::Red, //! "blue" => Color::Blue, //! "green" => Color::Green, //! _ => return Err(parser.into_other_error(&"could not parse Color")) //! }; //! Ok((color, parser)) //! } //! //! //! //! ``` //! //! # Cargo features //! //! These are the features of these crates: //! //! - `"iter"`(enabled by default): //! Enables all iteration items, including macros/functions that take/return iterators, //! //! - `"cmp"`(enabled by default): //! Enables all comparison functions and macros, //! the string equality and ordering comparison functions don't require this feature. //! //! - `"parsing_proc"`(enabled by default): //! Enables the `"parsing"` feature, compiles the `konst_proc_macros` dependency, //! and enables the [`parser_method`] macro. //! You can use this feature instead of `"parsing"` if the slightly longer //! compile times aren't a problem. //! //! - `"parsing"`(enabled by default): //! Enables the [`parsing`] module (for parsing from `&str` and `&[u8]`), //! the `primitive::parse_*` functions, `try_rebind`, and `rebind_if_ok` macros. //! //! - `"alloc"`: //! Enables items that use types from the [`alloc`] crate, including `Vec` and `String`. //! //! ### Rust release related //! //! None of thse features are enabled by default. //! //! - `"rust_latest_stable"`: enables the latest `"rust_1_*"` feature. //! Only recommendable if you can update the Rust compiler every stable release. //! //! - `"rust_1_83"`: //! Enables const functions that take mutable references, //! `array::{from_fn_, map_}` macros, and [`destructure`] macro. //! //! # No-std support //! //! `konst` is `#![no_std]`, it can be used anywhere Rust can be used. //! //! # Minimum Supported Rust Version //! //! `konst` requires Rust 1.65.0. //! //! Features that require newer versions of Rust, or the nightly compiler, //! need to be explicitly enabled with crate features. //! //! //! //! [`alloc`]: https://doc.rust-lang.org/alloc/ //! [`const_eq`]: ./macro.const_eq.html //! [`const_eq_for`]: ./macro.const_eq_for.html //! [`const_cmp`]: ./macro.const_cmp.html //! [`const_cmp_for`]: ./macro.const_cmp_for.html //! [`parsing`]: ./parsing/index.html //! [`primitive`]: ./primitive/index.html //! [`parser_method`]: macro.parser_method.html //! [`Parser`]: ./parsing/struct.Parser.html //! [`Parser::parse_u128`]: ./parsing/struct.Parser.html#method.parse_u128 //! [`destructure`]: ./macro.destructure.html //! #![deny(missing_docs)] #![deny(unused_results)] #![allow(rustdoc::redundant_explicit_links)] // clippy's opinionated BS #![allow(clippy::needless_doctest_main)] #![allow(clippy::init_numbered_fields)] //////////// #![forbid(clippy::missing_const_for_fn)] #![cfg_attr(feature = "docsrs", feature(doc_cfg))] #![no_std] #[cfg(feature = "alloc")] extern crate alloc; include! {"./root_module_macros.rs"} #[macro_use] #[doc(hidden)] pub mod macros; #[doc(hidden)] pub mod __for_cmp_impls; // pub mod other; #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] pub mod alloc_type; pub mod array; pub mod chr; #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub mod iter; /// const equivalents of `core::ffi` functions pub mod ffi; pub mod polymorphism; pub mod primitive; pub mod option; pub mod result; pub mod range; pub mod maybe_uninit; pub mod manually_drop; pub mod nonzero; pub mod other; #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] pub mod parsing; pub mod ptr; mod utils; #[allow(unused_imports)] mod utils_1_56 { pub(crate) use konst_kernel::__priv_transmute; } #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] pub use crate::parsing::Parser; #[cfg(feature = "parsing_proc")] #[doc(hidden)] pub use konst_proc_macros::{__priv_bstr_end, __priv_bstr_start}; pub mod slice; pub mod string; pub use ::const_panic; pub use crate::string::{cmp_str, eq_str}; #[doc(no_inline)] pub use crate::result::unwrap_ctx; #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub use crate::string::{cmp_option_str, eq_option_str}; #[cfg(all(doctest, feature = "iter", feature = "parsing_proc"))] #[doc = include_str!("../../README.md")] pub struct ReadmeTest; #[doc(hidden)] pub mod __ { pub use core::{ cmp::Ordering::{self, Equal, Greater, Less}, compile_error, marker::PhantomData, matches, mem::{self, ManuallyDrop}, ops::Range, option::Option::{self, None, Some}, primitive::usize, ptr, result::Result::{self, Err, Ok}, }; pub mod v { pub use core::{ option::Option::Some, result::Result::{Err, Ok}, }; } pub use crate::__for_cmp_impls::U8Ordering; pub use konst_kernel::utils::{__parse_closure_1, __parse_closure_2}; pub use konst_kernel::__::unit_array; pub use konst_kernel::{__priv_transmute, __split_array_type_and_closure, __unparenthesize_ty}; #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub use crate::cmp::{CmpWrapper, ConstCmp, IsAConstCmp, IsNotStdKind, IsStdKind}; pub use const_panic::concat_panic; } konst-0.3.16/src/macros/assert_cmp_macros.rs000064400000000000000000000153001046102023000171750ustar 00000000000000#[doc(hidden)] #[macro_export] macro_rules! __cmp_assert_inner { ($left:expr, $right:expr, $is_equal:ident, $operator:literal, $($($fmt:tt)+)?) => { match (&$left, &$right) { (left, right) => { if let $is_equal = $crate::coerce_to_cmp!($left).const_eq(right) { $crate::__::concat_panic!{ display: concat!( "\nassertion failed: LEFT ", $operator, " RIGHT\n left: `", ), left, "`\nright: `", right, "`\n", $( ": ", $($fmt)+)? } } } } } } macro_rules! cmp_assertc_docs { () => { concat!( "[**examples below**](#examples)", "\n\n", "This macro is only evaluated at compile-time if used in a context that requires it ", "(eg: in the expression assigned to a `const _: () = `)", "\n\n", "# Formatting ", "\n\n", "This uses the same syntax for formatting arguments as ", "[`const_panic::concat_panic`](macro@const_panic::concat_panic).", "\n\n", "By default, this only supports primitive types as arguments, ", "to format arrays or custom types you must enable ", r#"`const_panic`'s `"non_basic"` feature."#, "\n\n", "To pass user-defined types, ", "they must implement both of these traits as described in their docs:\n", "- [`konst::cmp::ConstCmp`](crate::cmp::ConstCmp)\n", "- [`const_panic::fmt::PanicFmt`]\n", "\n\n", ) }; } /// For asserting that two values are equal. /// #[doc = cmp_assertc_docs!()] /// /// # Examples /// /// ### Zipping slices /// /// This example requires the `"iter"` feature /// #[cfg_attr(feature = "iter", doc = "```rust")] #[cfg_attr(not(feature = "iter"), doc = "```ignore")] /// use konst::{iter, slice}; /// /// const A: &[u8] = &[3, 5, 8, 13]; /// const B: &[u8] = &[0, 1, 2, 3]; /// /// const C: &[(u8, u8)] = &{ /// konst::assertc_eq!(A.len(), B.len()); /// /// iter::collect_const!((u8, u8) => /// slice::iter_copied(A), /// zip(slice::iter_copied(B)), /// ) /// }; /// /// assert_eq!(C, [(3, 0), (5, 1), (8, 2), (13, 3)]); /// /// ``` /// /// If either slice was a different length, this would be the compile-time error: /// /// ```text /// error[E0080]: evaluation of constant value failed /// --> src/macros/assert_macros.rs:79:5 /// | /// 10 | konst::assertc_eq!(A.len(), B.len()); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at ' /// assertion failed: LEFT == RIGHT /// left: `3` /// right: `4` /// ', src/macros/assert_macros.rs:10:5 /// /// ``` /// /// ### User-defined type /// /// This example demonstrates formatting of user-defined types. /// /// The `const_panic::PanicFmt` derive that this example uses /// requres enabling `const_panic`'s `"derive"` feature. /// #[cfg_attr(feature = "__cp_derive", doc = "```rust")] #[cfg_attr(not(feature = "__cp_derive"), doc = "```ignore")] /// use konst::assertc_eq; /// use konst::const_panic::PanicFmt; /// /// const _: () = assert_same_layout(layout_for!(u32), layout_for!(i32)); /// /// #[track_caller] /// const fn assert_same_layout(left: Layout, right: Layout) { /// assertc_eq!{left, right, "layout mismatch"} /// } /// /// #[derive(PanicFmt)] /// struct Layout { /// type_name: &'static str, /// size: usize, /// alignment: usize, /// } /// /// konst::impl_cmp!{ /// impl Layout; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// konst::const_eq!(self.size, other.size) && /// konst::const_eq!(self.alignment, other.alignment) /// } /// } /// /// impl Layout { /// pub const fn new(type_name: &'static str) -> Self { /// Self { /// type_name, /// size: std::mem::size_of::(), /// alignment: std::mem::align_of::(), /// } /// } /// } /// /// macro_rules! layout_for { /// ($ty:ty) => { /// Layout::new::<$ty>(stringify!($ty)) /// } /// } use layout_for; /// /// # fn main(){} /// ``` /// /// If the types were changed, the example would fail compilation with this error: /// ```text /// error[E0080]: evaluation of constant value failed /// --> src/macros/assert_macros.rs:120:15 /// | /// 6 | const _: () = assert_same_layout(layout_for!(u32), layout_for!([u8; 4])); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at ' /// assertion failed: LEFT == RIGHT /// left: `Layout { type_name: "u32", size: 4, alignment: 4 }` /// right: `Layout { type_name: "[u8; 4]", size: 4, alignment: 1 }` /// : layout mismatch', src/macros/assert_macros.rs:6:15 /// /// ``` /// #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! assertc_eq { ($left:expr, $right:expr $(, $($fmt:tt)* )? ) => ( $crate::__cmp_assert_inner!{$left, $right, false, "==", $($($fmt)*)?} ); } /// For asserting that two values are unequal. /// #[doc = cmp_assertc_docs!()] /// /// # Examples /// /// ### Unique strings /// /// ```rust /// assert_eq!(NAMES, ["bob", "matt", "rob"]); /// /// const NAMES: &[&str] = assert_unique(&["bob", "matt", "rob"]); /// /// #[track_caller] /// const fn assert_unique<'a, 'b>(names: &'a [&'b str]) -> &'a [&'b str] { /// konst::for_range!{x in 0..names.len() => /// konst::for_range!{y in 0..names.len() => /// if x == y { continue } /// konst::assertc_ne!{ /// names[x], /// names[y], /// "equal names at index `", x, "` and `", y, "`" /// } /// } /// } /// names /// } /// /// ``` /// /// If the argument had repeated strings, this would be the error: /// /// ```text /// error[E0080]: evaluation of constant value failed /// --> src/macros/assert_macros.rs:126:24 /// | /// 6 | const NAMES: &[&str] = assert_unique(&["bob", "matt", "rob", "rob"]); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at ' /// assertion failed: LEFT != RIGHT /// left: `"rob"` /// right: `"rob"` /// : equal names at index `2` and `3`', src/macros/assert_macros.rs:6:24 /// /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! assertc_ne { ($left:expr, $right:expr $(, $($fmt:tt)* )? ) => ( $crate::__cmp_assert_inner!{$left, $right, true, "!=", $($($fmt)*)?} ); } konst-0.3.16/src/macros/bytes_fn_macros.rs000064400000000000000000000024771046102023000166610ustar 00000000000000macro_rules! impl_bytes_function { ( strip_prefix; left = $left:expr; right = $right:expr; on_error = $on_error:expr, ) => { if $left.len() < $right.len() { $on_error } loop { match ($left, $right) { ([lb, rem_slice @ ..], [rb, rem_matched @ ..]) => { $left = rem_slice; $right = rem_matched; if *lb != *rb { $on_error } } (rem, _) => { $left = rem; break; } } } }; ( strip_suffix; left = $left:expr; right = $right:expr; on_error = $on_error:expr, ) => { if $left.len() < $right.len() { $on_error } loop { match ($left, $right) { ([rem_slice @ .., lb], [rem_matched @ .., rb]) => { $left = rem_slice; $right = rem_matched; if *lb != *rb { $on_error } } (rem, _) => { $left = rem; break; } } } }; } konst-0.3.16/src/macros/const_eq_macros.rs000064400000000000000000000254751046102023000166660ustar 00000000000000/// Compares two values for equality. /// /// The arguments must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_eq` method taking a reference. /// /// # Limitations /// /// The arguments must be concrete types, and have a fully inferred type. /// eg: if you pass an integer literal it must have a suffix to indicate its type. /// /// # Example /// /// ```rust /// use konst::{const_eq, impl_cmp}; /// /// use std::ops::Range; /// /// struct Fields<'a> { /// foo: u32, /// bar: Option, /// baz: Range, /// qux: &'a str, /// } /// /// impl_cmp!{ /// impl['a] Fields<'a>; /// pub const fn const_eq(&self, other: &Self) -> bool { /// self.foo == other.foo && /// const_eq!(self.bar, other.bar) && /// const_eq!(self.baz, other.baz) && /// const_eq!(self.qux, other.qux) /// } /// } /// /// const _: () = { /// let foo = Fields { /// foo: 10, /// bar: None, /// baz: 10..20, /// qux: "hello", /// }; /// /// let bar = Fields { /// foo: 99, /// bar: Some(true), /// baz: 0..5, /// qux: "world", /// }; /// /// assert!( const_eq!(foo, foo)); /// assert!(!const_eq!(foo, bar)); /// assert!(!const_eq!(bar, foo)); /// assert!( const_eq!(bar, bar)); /// }; /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! const_eq { ($left:expr, $right:expr $(,)*) => { match $crate::coerce_to_cmp!($left, $right) { (left, right) => left.const_eq(right), } }; } /// Compares two standard library types for equality, /// that can't be compared with [`const_eq`]. /// /// /// # Types /// /// This macro supports multiple types with different prefixes: /// /// - `slice`: for comparing `&[T]`. [example](#compare_slices_structs) /// /// - `option`: for comparing `Option`. [example](#compare_options) /// /// - `range`: for comparing `Range`. [example](#compare_ranges) /// /// - `range_inclusive`: for comparing `RangeInclusive`. /// [example](#compare_ranges_incluside) /// /// /// # Limitations /// /// The arguments must be concrete types, and have a fully inferred type. /// eg: if you pass an integer literal it must have a suffix to indicate its type. /// /// /// # Arguments /// /// The arguments take this form /// /// ```text /// const_eq_for!(type; left_value, right_value ) /// ``` /// /// ### Comparator argument /// /// The `` argument can be any of: /// /// - ` `(passing nothing): Compares the item using the [`const_eq`] macro. /// [example](#compare_slices_structs) /// /// - `, |item| `: /// Converts the item with `` to a type that can be compared using the /// [`const_eq`] macro. /// [example](#compare_slices_fieldless_enums) /// /// - `, |left_item, right_item| `: /// Compares the items with ``, which must evaluate to a `bool`. /// [example](#compare_options) /// /// - `, path::to::function`: /// Compares the items using the passed function, which must evaluate to a `bool`. /// [example](#compare_ranges_incluside) /// /// /// /// # Examples /// /// /// ### Comparing slices of structs /// /// ``` /// use konst::{const_eq_for, eq_str}; /// /// #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// pub struct Location { /// pub file: &'static str, /// pub column: u32, /// pub line: u32, /// } /// /// konst::impl_cmp! { /// impl Location; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// eq_str(self.file, other.file) && /// self.column == other.column && /// self.line == other.line /// } /// } /// # /// # macro_rules! here { /// # () => { /// # $crate::Location{file: file!(), column: column!(), line: line!()} /// # } /// # } /// # /// /// # fn main () { /// const HERE: &[Location] = &[here!(), here!(), here!(), here!()]; /// /// const THERE: &[Location] = &[here!(), here!(), here!(), here!()]; /// /// const _: () = { /// assert!( const_eq_for!(slice; HERE, HERE)); /// assert!(!const_eq_for!(slice; HERE, THERE)); /// assert!( const_eq_for!(slice; THERE, THERE)); /// }; /// # } /// /// ``` /// /// /// ### Comparing slices of field-less enums /// /// ```rust /// #[derive(Copy, Clone)] /// enum Direction { /// Left, /// Right, /// Up, /// Down, /// } /// /// use Direction::*; /// /// const fn eq_slice_direction(left: &[Direction], right: &[Direction]) -> bool { /// konst::const_eq_for!(slice; left, right, |&x| x as u8) /// } /// /// const CHEAT_CODE: &[Direction] = &[Up, Up, Down, Down, Left, Right, Left, Right]; /// /// const CLOCKWISE: &[Direction] = &[Up, Right, Down, Left]; /// /// const _: () = { /// assert!( eq_slice_direction(CHEAT_CODE, CHEAT_CODE)); /// assert!(!eq_slice_direction(CHEAT_CODE, CLOCKWISE)); /// assert!( eq_slice_direction(CLOCKWISE, CLOCKWISE)); /// }; /// /// ``` /// /// /// ### Comparing `Option`s /// /// ```rust /// use konst::const_eq_for; /// /// const SOME: Option<(u32, u32)> = Some((3, 5)); /// const NONE: Option<(u32, u32)> = None; /// /// const fn eq_opt_tuple(left: &Option<(u32, u32)>, right: &Option<(u32, u32)>) -> bool { /// const_eq_for!(option; left, right, |l, r| l.0 == r.0 && l.1 == r.1 ) /// } /// /// const _: () = { /// assert!( eq_opt_tuple(&SOME, &SOME)); /// assert!(!eq_opt_tuple(&SOME, &NONE)); /// assert!( eq_opt_tuple(&NONE, &NONE)); /// }; /// /// ``` /// /// /// /// ### Comparing `Range`s /// /// ```rust /// use konst::{const_eq_for, impl_cmp}; /// /// use std::ops::Range; /// /// #[derive(Copy, Clone)] /// pub enum Month { /// January, /// February, /// March, /// April, /// May, /// June, /// July, /// August, /// September, /// October, /// November, /// December, /// } /// /// use Month::*; /// /// konst::impl_cmp! { /// impl Month; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// *self as u8 == *other as u8 /// } /// } /// /// const FOO: Range = January..April; /// const BAR: Range = October..December; /// /// const _: () = { /// assert!( const_eq_for!(range; FOO, FOO)); /// assert!(!const_eq_for!(range; FOO, BAR)); /// assert!( const_eq_for!(range; BAR, BAR)); /// }; /// /// ``` /// /// /// ### Comparing `RangeInclusive`s /// /// ```rust /// use konst::{const_eq_for, impl_cmp}; /// /// use std::ops::RangeInclusive; /// /// #[derive(Copy, Clone)] /// pub enum WeekDay { /// Monday, /// Tuesday, /// Wednesday, /// Thursday, /// Friday, /// Saturday, /// Sunday, /// } /// /// use WeekDay::*; /// /// konst::impl_cmp! { /// impl WeekDay; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// *self as u8 == *other as u8 /// } /// } /// /// const FOO: RangeInclusive = Monday..=Thursday; /// const BAR: RangeInclusive = Friday..=Sunday; /// /// const _: () = { /// assert!( const_eq_for!(range_inclusive; FOO, FOO)); /// assert!(!const_eq_for!(range_inclusive; FOO, BAR, WeekDay::const_eq)); /// assert!( const_eq_for!(range_inclusive; BAR, BAR, WeekDay::const_eq)); /// }; /// /// ``` /// /// [`ConstCmp`]: const::cmp::ConstCmp /// [`const_eq`]: macro.const_eq.html #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! const_eq_for { ( slice; $left_slice:expr, $right_slice:expr $(, $($comparison:tt)* )? ) => { match ($left_slice, $right_slice) { (left_slice, right_slice) => { let mut returned = left_slice.len() == right_slice.len(); if returned { let mut i = 0; while i != left_slice.len() { let are_eq = $crate::__priv_const_eq_for!( left_slice[i], right_slice[i], $( $($comparison)* )? ); if !are_eq { returned = false; break; } i += 1; } } returned } } }; ( option; $left_opt:expr, $right_opt:expr $(, $($comparison:tt)* )? ) => { match (&$left_opt, &$right_opt) { (Some(l), Some(r)) => $crate::__priv_const_eq_for!(*l, *r, $( $($comparison)* )?), (None, None) => true, _ => false, } }; ( range; $left_range:expr, $right_range:expr $(, $($comparison:tt)* )? ) => { match (&$left_range, &$right_range) { (left_range, right_range) => { $crate::__priv_const_eq_for!( left_range.start, right_range.start, $( $($comparison)* )? ) && $crate::__priv_const_eq_for!( left_range.end, right_range.end, $( $($comparison)* )? ) } } }; ( range_inclusive; $left_range:expr, $right_range:expr $(, $($comparison:tt)* )? ) => { match (&$left_range, &$right_range) { (left_range, right_range) => { $crate::__priv_const_eq_for!( left_range.start(), right_range.start(), $( $($comparison)* )? ) && $crate::__priv_const_eq_for!( left_range.end(), right_range.end(), $( $($comparison)* )? ) } } }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_const_eq_for { ($left:expr, $right:expr, ) => { $crate::coerce_to_cmp!($left).const_eq(&$right) }; ($left:expr, $right:expr, |$l:pat_param| $key_expr:expr $(,)*) => { $crate::coerce_to_cmp!({ let $l = &$left; $key_expr }) .const_eq(&{ let $l = &$right; $key_expr }) }; ($left:expr, $right:expr, |$l:pat_param, $r:pat_param| $eq_expr:expr $(,)*) => {{ let $l = &$left; let $r = &$right; $eq_expr }}; ($left:expr, $right:expr, $func:path $(,)*) => { $func(&$left, &$right) }; } konst-0.3.16/src/macros/const_ord_macros.rs000064400000000000000000000215111046102023000170300ustar 00000000000000/// Compares two values for ordering. /// /// The arguments must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_cmp` method taking a reference. /// /// # Limitations /// /// The arguments must be concrete types, and have a fully inferred type. /// eg: if you pass an integer literal it must have a suffix to indicate its type. /// /// # Example /// /// ```rust /// use konst::{const_cmp, impl_cmp, try_equal}; /// /// use std::cmp::Ordering; /// /// struct Fields<'a> { /// foo: u32, /// bar: Option, /// baz: Ordering, /// qux: &'a str, /// } /// /// impl_cmp!{ /// impl['a] Fields<'a>; /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// try_equal!(const_cmp!(self.foo, other.foo)); /// try_equal!(const_cmp!(self.bar, other.bar)); /// try_equal!(const_cmp!(self.baz, other.baz)); /// try_equal!(const_cmp!(self.qux, other.qux)) /// } /// } /// /// const _: () = { /// let foo = Fields { /// foo: 10, /// bar: None, /// baz: Ordering::Less, /// qux: "hello", /// }; /// /// let bar = Fields { /// foo: 99, /// bar: Some(true), /// baz: Ordering::Greater, /// qux: "world", /// }; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(matches!(const_cmp!(bar, bar), Ordering::Equal)); /// }; /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! const_cmp { ($left:expr, $right:expr $(,)*) => { match $crate::coerce_to_cmp!($left, $right) { (left, right) => left.const_cmp(right), } }; } /// Compares two standard library types for ordering, /// that can't be compared with [`const_cmp`]. /// /// This macro takes the same /// [types](macro.const_eq_for.html#types-section) (except for range types), /// has the same [limitations](macro.const_eq_for.html#limitations-section), /// and takes [arguments of the same form](macro.const_eq_for.html#arguments-section) /// as the [`const_eq_for`] macro /// /// # Examples /// /// ### Slices /// /// ```rust /// use konst::{const_cmp, const_cmp_for, try_equal}; /// /// use std::cmp::Ordering; /// /// const fn cmp_slice_pair(left: &[(u32, u32)], right: &[(u32, u32)]) -> Ordering { /// const_cmp_for!(slice; left, right, |l, r|{ /// try_equal!(const_cmp!(l.0, r.0)); /// try_equal!(const_cmp!(l.1, r.1)) /// }) /// } /// /// const _: () = { /// let foo = &[(0, 1), (1, 2), (3, 4), (5, 6)]; /// let bar = &[(0, 1), (3, 4), (5, 6), (7, 8)]; /// /// assert!(matches!(cmp_slice_pair(foo, foo), Ordering::Equal)); /// assert!(matches!(cmp_slice_pair(foo, bar), Ordering::Less)); /// assert!(matches!(cmp_slice_pair(bar, foo), Ordering::Greater)); /// assert!(matches!(cmp_slice_pair(bar, bar), Ordering::Equal)); /// }; /// ``` /// /// /// ### Options /// /// ```rust /// use konst::{const_cmp, const_cmp_for, try_equal}; /// /// use std::cmp::Ordering; /// /// #[derive(Copy, Clone)] /// enum Shape { /// Square, /// Circle, /// Line, /// } /// /// const fn cmp_opt_pair(left: Option, right: Option) -> Ordering { /// const_cmp_for!(option; left, right, |x| *x as u8 ) /// } /// /// const _: () = { /// let foo = Some(Shape::Square); /// let bar = Some(Shape::Circle); /// let baz = Some(Shape::Line); /// /// assert!(matches!(cmp_opt_pair(foo, foo), Ordering::Equal)); /// assert!(matches!(cmp_opt_pair(foo, bar), Ordering::Less)); /// assert!(matches!(cmp_opt_pair(foo, baz), Ordering::Less)); /// /// assert!(matches!(cmp_opt_pair(bar, foo), Ordering::Greater)); /// assert!(matches!(cmp_opt_pair(bar, bar), Ordering::Equal)); /// assert!(matches!(cmp_opt_pair(bar, baz), Ordering::Less)); /// /// assert!(matches!(cmp_opt_pair(baz, foo), Ordering::Greater)); /// assert!(matches!(cmp_opt_pair(baz, bar), Ordering::Greater)); /// assert!(matches!(cmp_opt_pair(baz, baz), Ordering::Equal)); /// }; /// /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp /// [`const_cmp`]: macro.const_cmp.html /// [`cmp::Ordering`]: https://doc.rust-lang.org/core/cmp/enum.Ordering.html /// #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! const_cmp_for { ( slice; $left_slice:expr, $right_slice:expr $(, $($comparison:tt)* )? ) => { match ($left_slice, $right_slice) {(mut left_slice, mut right_slice) => { use $crate::__::Ordering as CmpOrdering; if left_slice.len() == right_slice.len() { loop{ if let ([l, l_rem@..], [r, r_rem@..]) = (left_slice, right_slice) { left_slice = l_rem; right_slice = r_rem; let ord = $crate::__priv_const_cmp_for!{ *l, *r, $($($comparison)*)? }; if !$crate::__::matches!(ord, $crate::__::Ordering::Equal) { break ord; } } else { break $crate::__::Ordering::Equal } } } else if left_slice.len() < right_slice.len() { CmpOrdering::Less } else { CmpOrdering::Greater } }} }; ( option; $left_opt:expr, $right_opt:expr $(, $($comparison:tt)* )? ) => { match (&$left_opt, &$right_opt) { (Some(l), Some(r)) => $crate::__priv_const_cmp_for!(*l, *r, $( $($comparison)* )?), (Some(_), None) => $crate::__::Greater, (None, Some(_)) => $crate::__::Less, (None, None) => $crate::__::Equal, } }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_const_cmp_for { ($left:expr, $right:expr, ) => { $crate::coerce_to_cmp!(&$left).const_cmp(&$right) }; ($left:expr, $right:expr, |$l:pat_param| $key_expr:expr $(,)*) => { $crate::coerce_to_cmp!({ let $l = &$left; $key_expr }) .const_cmp(&{ let $l = &$right; $key_expr }) }; ($left:expr, $right:expr, |$l:pat_param, $r:pat_param| $eq_expr:expr $(,)*) => {{ let $l = &$left; let $r = &$right; $eq_expr }}; ($left:expr, $right:expr, $func:path $(,)*) => {{ $func(&$left, &$right) }}; } /// Evaluates to `$ord` if it is `Ordering::Equal`, /// otherwise returns it from the enclosing function. /// /// # Example /// /// ```rust /// use konst::{const_cmp, impl_cmp, try_equal}; /// /// use std::cmp::Ordering; /// /// struct Fields<'a> { /// first: &'a [u8; 4], /// second: bool, /// third: Option<&'static str>, /// } /// /// impl_cmp!{ /// impl['a] Fields<'a>; /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// try_equal!(const_cmp!(self.first, other.first)); /// try_equal!(const_cmp!(self.second, other.second)); /// try_equal!(const_cmp!(self.third, other.third)) /// } /// } /// /// const _: () = { /// let foo = Fields { /// first: &[3, 5, 8, 13], /// second: false, /// third: None, /// }; /// /// let bar = Fields { /// first: &[5, 8, 13, 14], /// second: true, /// third: Some("what!?"), /// }; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(matches!(const_cmp!(bar, bar), Ordering::Equal)); /// }; /// /// ``` /// #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! try_equal { (break $ord:expr $(,)*) => { match $ord { $crate::__::Ordering::Equal => $crate::__::Ordering::Equal, ord => return ord, } }; ($ord:expr $(,)*) => { match $ord { $crate::__::Ordering::Equal => $crate::__::Ordering::Equal, ord => return ord, } }; (break; $ord:expr $(,)*) => { match $ord { $crate::__::Ordering::Equal => $crate::__::Ordering::Equal, ord => return ord, } }; } #[cfg(feature = "cmp")] macro_rules! cmp_int { ($l:expr, $r:expr $(,)*) => {{ if $l == $r { Ordering::Equal } else if $l < $r { Ordering::Less } else { Ordering::Greater } }}; } konst-0.3.16/src/macros/control_flow.rs000064400000000000000000000020101046102023000161720ustar 00000000000000/// Emulates the [inline const feature](`const{ ... }`) in pre-1.79 versions. /// /// As opposed to inline const, you must pass the type that the expression evaluates to. /// /// # Limitations /// /// This can't be used with expressions that reference generic parameters. /// /// # Example /// /// ```rust /// use konst::{konst, eq_str}; /// /// const FOO: &str = "hello"; /// /// # const _: bool = konst!{bool, eq_str(FOO, "hi")}; /// # /// // By using `konst` here, the function is unconditionally evaluated at compile-time. /// if konst!{bool, eq_str(FOO, "hi")} { /// panic!("The constants are equal, this wasn't supposed to happen!!"); /// } /// /// ``` /// /// [Rust 1.79.0]: /// https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.html#inline-const-expressions /// /// [inline const feature]: /// https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.html#inline-const-expressions #[macro_export] macro_rules! konst { ($type:ty, $expr:expr $(,)*) => {{ const __KONST__: $type = $expr; __KONST__ }}; } konst-0.3.16/src/macros/declare_cmp_fn_macros.rs000064400000000000000000000231731046102023000177650ustar 00000000000000#[doc(hidden)] #[macro_export] macro_rules! __declare_string_cmp_fns { ( import_path = $path:expr, equality_fn = $eq_str:ident, ordering_fn = $cmp_str:ident, /// Equivalent to ordering_fn, but returns a U8Ordering ordering_fn_inner = $cmp_str_inner:ident, ) => { $crate::__declare_string_cmp_fns! { @inner equality_fn = $eq_str, ordering_fn = $cmp_str, use_eq_str = concat!("use ", $path, "::", stringify!($eq_str), ";"), use_cmp_str = concat!("use ", $path, "::", stringify!($cmp_str), ";"), } }; (@inner equality_fn = $eq_str:ident, ordering_fn = $cmp_str:ident, use_eq_str = $eq_str_import:expr, use_cmp_str = $cmp_str_import:expr, ) => { $crate::__delegate_const_eq! { skip_coerce; /// A const equivalent of `&str` equality comparison. /// /// # Example /// /// ```rust #[doc = $eq_str_import] /// /// const FOO: &str = "foo"; /// const BAR: &str = "fooooo"; /// const BAZ: &str = "bar"; /// /// /// const FOO_EQ_FOO: bool = eq_str(FOO, FOO); /// assert!( FOO_EQ_FOO ); /// /// const FOO_EQ_BAR: bool = eq_str(FOO, BAR); /// assert!( !FOO_EQ_BAR ); /// /// const FOO_EQ_BAZ: bool = eq_str(FOO, BAZ); /// assert!( !FOO_EQ_BAZ ); /// /// ``` /// #[inline] pub const fn eq_str(ref left: &str, right: &str) -> bool { let left = left.as_bytes(); let right = right.as_bytes(); if left.len() != right.len() { return false; } let mut i = 0; while i != left.len() { if left[i] != right[i] { return false; } i += 1; } true } } __delegate_const_ord! { skip_coerce; /// A const equivalent of `str::cmp`. /// /// # Example /// /// ```rust #[doc = $cmp_str_import] /// /// use std::cmp::Ordering; /// /// const FOO: &str = "foo"; /// const BAR: &str = "fooooo"; /// const BAZ: &str = "bar"; /// /// /// const FOO_CMP_FOO: Ordering = cmp_str(FOO, FOO); /// assert_eq!(FOO_CMP_FOO, Ordering::Equal); /// /// const FOO_CMP_BAR: Ordering = cmp_str(FOO, BAR); /// assert_eq!(FOO_CMP_BAR, Ordering::Less); /// /// const FOO_CMP_BAZ: Ordering = cmp_str(FOO, BAZ); /// assert_eq!(FOO_CMP_BAZ, Ordering::Greater); /// /// ``` /// #[inline] pub const fn cmp_str(ref left: &str, right: &str) -> $crate::__::Ordering { cmp_str_inner(left.as_bytes(), right.as_bytes()).to_ordering() } } #[inline] const fn cmp_str_inner(left: &[u8], right: &[u8]) -> $crate::__::U8Ordering { use $crate::__::U8Ordering; let left_len = left.len(); let right_len = right.len(); let (min_len, on_ne) = if left_len < right_len { (left_len, U8Ordering::LESS) } else { (right_len, U8Ordering::GREATER) }; let mut i = 0; while i < min_len { $crate::__priv_ret_if_ne! {left[i], right[i]} i += 1; } if left_len == right_len { U8Ordering::EQUAL } else { on_ne } } }; } #[doc(hidden)] #[macro_export] macro_rules! __declare_slice_cmp_fns{ ( import_path = $path:expr, $(( $(#[$attr_both:meta])*, $(#[$attr_eq:meta])*, $(#[$attr_ord:meta])*, $type:ty, $eq_fn_name:ident, $cmp_fn_name:ident, ))* )=>{ $( __declare_slice_cmp_fns!{ @step_two import_path = $path, $(#[$attr_both])*, $(#[$attr_eq])*, $(#[$attr_ord])*, concat!( "Compares two `&[", stringify!($type), "]` for equality.", ), concat!( "Compares two `&[", stringify!($type), "]`, returning the order of `left` relative to `right`.", ), $type, $eq_fn_name, $cmp_fn_name, } )* }; (@step_two import_path = $path:expr, $(#[$attr_both:meta])*, $(#[$attr_eq:meta])*, $(#[$attr_ord:meta])*, $docs_eq:expr, $docs_ord:expr, $ty:ty, $eq_fn_name:ident, $cmp_fn_name:ident, ) => { $crate::__delegate_const_eq!{ skip_coerce; #[doc = $docs_eq] $(#[$attr_both])* $(#[$attr_eq])* #[inline] pub const fn $eq_fn_name(ref left: &[$ty], right: &[$ty]) -> bool { if left.len() != right.len() { return false; } let mut i = 0; while i != left.len() { if left[i] != right[i] { return false; } i += 1; } true } } __delegate_const_ord!{ skip_coerce; for['a,] #[doc = $docs_ord] $(#[$attr_both])* $(#[$attr_ord])* #[inline] pub const fn $cmp_fn_name(ref left: &[$ty], right: &[$ty]) -> $crate::__::Ordering { use $crate::__::U8Ordering; const fn cmp_inner(left: &[$ty], right: &[$ty]) -> $crate::__::U8Ordering { let left_len = left.len(); $crate::__priv_ret_if_ne! {left_len, right.len()} let mut i = 0; while i < left_len { $crate::__priv_ret_if_ne! {left[i], right[i]} i += 1; } U8Ordering::EQUAL } cmp_inner(left, right).to_ordering() } } }; } #[doc(hidden)] #[macro_export] macro_rules! __declare_fns_with_docs{ ( $(($($args:tt)*))* docs $docs:tt macro = $macro:ident ! $macro_prefix:tt, )=>{ $( $crate::__declare_fns_with_docs!{ @inner ($($args)*) docs $docs macro = $macro ! $macro_prefix, } )* }; (@inner ( $type:ty, ($($func_name:ident),* $(,)?) $($rem:tt)* ) docs( $(($before:expr, $after:expr))* ) macro = $macro:ident ! ($($prefix:tt)*), ) => { $macro!{ $($prefix)* ($type, ($($func_name),*) $($rem)* ) docs( $(concat!($before, stringify!($type), $after)),* ) } }; (@inner ( $type:ty, ($($func_name:ident),* $(,)?) $($rem:tt)* ) docs(default) macro = $macro:ident ! ($($prefix:tt)*), ) => { $macro!{ $($prefix)* ($type, ($($func_name),*) $($rem)* ) docs( concat!( "Compares two `", stringify!($type), "` for equality.", ), concat!( "Compares two `", stringify!($type), "`, returning the ordering of `left` relative to `right`." ), ) } }; } macro_rules! __impl_option_cmp_fns { ( $(#[$attr:meta])* $(for[$($impl:tt)*])? params($l:ident, $r:ident) eq_comparison = $eq_comparison:expr, cmp_comparison = $cmp_comparison:expr, parameter_copyability = $copyab:ident, ($type:ty, ($eq_fn_name:ident, $cmp_fn_name:ident)) docs( $docs_eq:expr, $docs_cmp:expr, ) ) => ( __delegate_const_eq!{ $(for[$($impl)*])? #[doc = $docs_eq] $(#[$attr])* pub const fn $eq_fn_name($copyab left: $type, right: $type) -> bool { match (left, right) { (Some($l), Some($r)) => $eq_comparison, (None, None) => true, _ => false, } } } __delegate_const_ord!{ $(for[$($impl)*])? #[doc = $docs_cmp] $(#[$attr])* pub const fn $cmp_fn_name($copyab left: $type, right: $type) -> core::cmp::Ordering { use core::cmp::Ordering; match (left, right) { (Some($l), Some($r)) => $cmp_comparison, (Some(_), None) => Ordering::Greater, (None, Some(_)) => Ordering::Less, (None, None) => Ordering::Equal, } } } ) } konst-0.3.16/src/macros/declare_generic_const.rs000064400000000000000000000014511046102023000177740ustar 00000000000000macro_rules! declare_generic_const { ( $( $(#[$meta:meta])* for[$($gen_param:tt)*] $vis:vis const $name:ident [$($lt:lifetime,)* $($ty:ident),* $(; $($const:ident),*)? ] :$ret:ty = $value:expr; )* ) => { $( $(#[$meta])* #[allow(non_camel_case_types)] $vis struct $name<$($gen_param)*>( core::marker::PhantomData<( $( core::marker::PhantomData<&$lt ()>, )* $( core::marker::PhantomData<$ty>, )* )> ); impl<$($gen_param)*> $name<$($lt,)* $($ty,)* $($($const,)*)? > { /// The value that this constructs. $vis const V: $ret = $value; } )* }; } konst-0.3.16/src/macros/destructuring.rs000064400000000000000000000467121046102023000164060ustar 00000000000000#![expect(non_camel_case_types)] use core::marker::PhantomData; use core::mem::ManuallyDrop; ////// #[doc(hidden)] pub trait __GetImplsHelper { type T: ?Sized; fn __impls_drop_iwrhqlpnnieu8c6w(&self) -> __DoesNotImplDrop; } ////// #[doc(hidden)] pub struct __ImplsDrop(PhantomData T>); ////// #[doc(hidden)] pub struct __DoesNotImplDrop(PhantomData T>); impl __DoesNotImplDrop { pub const fn new(_: *mut T) -> Self { Self(PhantomData) } } ////// #[doc(hidden)] pub struct __GetImpls_IWRHQLPNNIEU8C6W(pub PhantomData T>); impl __GetImplsHelper for __GetImpls_IWRHQLPNNIEU8C6W { type T = T; fn __impls_drop_iwrhqlpnnieu8c6w(&self) -> __DoesNotImplDrop { __DoesNotImplDrop(PhantomData) } } #[expect(drop_bounds)] impl __GetImpls_IWRHQLPNNIEU8C6W where // I really do mean to test for Drop, // because it's to destructure a struct into its fields T: Drop, { pub fn __impls_drop_iwrhqlpnnieu8c6w(self) -> __ImplsDrop { __ImplsDrop(PhantomData) } } ////// #[doc(hidden)] #[inline(always)] pub const fn cast_manuallydrop_ptr(ptr: *mut ManuallyDrop) -> *mut T { ptr.cast() } #[doc(hidden)] #[inline(always)] /// Gets a pointer to the first elem in a ManuallyDrop array pub const fn cast_manuallydrop_array_ptr( ptr: *mut ManuallyDrop<[T; N]>, ) -> *mut T { ptr.cast() } #[doc(hidden)] #[inline(always)] pub const fn cast_ptr_with_phantom(ptr: *mut T, _phantom: PhantomData U>) -> *mut U { ptr.cast() } #[doc(hidden)] #[inline(always)] pub const fn get_phantom_len( _phantom: PhantomData [T; N]>, ) -> usize { N } #[doc(hidden)] #[inline(always)] pub const fn make_it() -> T { loop {} } #[doc(hidden)] #[inline(always)] pub const fn fake_read(_: *mut T) -> T { loop {} } #[doc(hidden)] #[inline(always)] pub const fn make_phantom(_: *mut T) -> PhantomData T> { PhantomData } #[doc(hidden)] #[inline(always)] pub const fn array_into_phantom( val: [T; N], ) -> PhantomData [T; N]> { core::mem::forget(val); PhantomData } #[doc(hidden)] #[inline(always)] pub const fn assert_same_type(this: T, that: T) { core::mem::forget(this); core::mem::forget(that); } ////// #[doc(hidden)] pub type __ArrayManuallyDrop = ManuallyDrop<[T; LEN]>; ////// /// Destructures a struct/tuple/array into all of its elements/fields. /// /// [**for examples look here**](#examples) /// /// # Motivation /// /// This macro works around a limitation of Rust as of 1.83, /// where in a const context, a non-`Drop` type can't be destructured into its elements/fields /// if any of them is `Drop`. /// /// Even simple cases like this don't compile: /// /// ```rust,compile_fail /// const fn foo((a, b): (T, T)) -> [T; 2] { /// [a, b] /// } /// ``` /// /// ```text /// error[E0493]: destructor of `(T, T)` cannot be evaluated at compile-time /// --> src/lib.rs:1:17 /// | /// 1 | const fn foo((a, b): (T, T)) -> [T; 2] { /// | ^^^^^^ the destructor for this type cannot be evaluated in constant functions /// 2 | [a, b] /// 3 | } /// | - value is dropped here /// ``` /// /// # Requirements/Limitations /// /// This macro has these requirements and limitations: /// - it does not support `..` patterns in tuples or structs /// (because unmentioned fields would be leaked), /// but `..` patterns are supported in arrays. /// - it requires that passed-in structs do not impl `Drop` /// (like built-in destructuring does), /// but any field can impl `Drop`. /// - it needs to be invoked multiple times /// to destructure nested structs/tuples/arrays that have `Drop` elements/fields. /// [(example)](#nested-destructuring) /// - it only supports tuple structs and tuples up to 16 elements (inclusive) /// /// # Syntax /// /// This section uses a pseudo-macro_rules syntax for each type of input. /// /// ### Braced structs /// /// ```text /// $struct_path:brace_path {$($field:tt $(: $pattern:pat)?),* $(,)?} /// $(:$struct_ty:ty)? /// = $val:expr /// ``` /// /// Where `:brace_path` can be either of: /// - `$(::)? $($path:ident)::* $(,)?` /// - `$struct_path:path $(,)?` /// /// [example below](#braced-struct) /// /// ### Tuple structs /// /// ```text /// $struct_path:tuple_path ( $($pattern:pat),* $(,)? ) /// $(:$struct_ty:ty)? /// = $val:expr /// ``` /// /// Where `:tuple_path` can be either of: /// - `$(::)? $($path:ident)::* $(,)?` /// - `$struct_path:path ,` (braced struct patterns don't need the `,`) /// /// [example below](#tuple-struct) /// /// ### Tuples /// /// ```text /// ( $($pattern:pat),* $(,)? ) $(:$tuple_ty:ty)? = $val:expr /// ``` /// [example below](#tuple) /// /// ### Arrays /// /// ```text /// [$( $pat:elem_pat $(@ ..)? ),* $(,)?] $(:$array_ty:ty)? = $val:expr /// /// Where `:elem_pat` can be any of: /// - `_` /// - `..` /// - `$ident:ident` /// - `($pattern:pat)`: any pattern inside of parentheses /// ``` /// [example below](#array) /// /// # Examples /// /// These examples demonstrate destructuring non-Copy types in const, /// which can't be done with built-in destructuring as of Rust 1.83. /// /// ### Braced Struct /// /// ```rust /// use std::ops::Range; /// /// assert_eq!(PAIR, (3, 5)); /// /// const PAIR: (u32, u32) = range_to_pair(3..5); /// /// const fn range_to_pair(range: Range) -> (T, T) { /// konst::destructure!{Range{start, end} = range} /// /// (start, end) /// } /// ``` /// /// ### Tuple Struct /// /// ```rust /// /// assert_eq!(PAIR, [8, 13]); /// /// const PAIR: [u32; 2] = Pair(8, 13).into_inner(); /// /// struct Pair(T, T); /// /// impl Pair { /// const fn into_inner(self) -> [T; 2] { /// konst::destructure!{Self(first, second) = self} /// /// [first, second] /// } /// } /// ``` /// /// ### Tuple /// /// ```rust /// /// assert_eq!(PAIR, (5, String::new())); /// /// const PAIR: (u32, String) = swap_pair((String::new(), 5)); /// /// const fn swap_pair(pair: (T, U)) -> (U, T) { /// konst::destructure!{(a, b) = pair} /// /// (b, a) /// } /// ``` /// /// ### Array /// /// ```rust /// /// assert_eq!(SPLIT, (Some(String::new()), [None, None, Some(String::new())])); /// /// const SPLIT: (Option, [Option; 3]) = /// split_first([Some(String::new()), None, None, Some(String::new())]); /// /// const fn split_first(array: [T; 4]) -> (T, [T; 3]) { /// konst::destructure!{[a, rem @ ..] = array} /// /// (a, rem) /// } /// ``` /// /// ### Nested Destructuring /// /// ```rust /// /// assert_eq!(TRIPLE, [3, 5, 8]); /// /// const TRIPLE: [u8; 3] = flatten((3, (5, 8))); /// /// const fn flatten(tup: (T, (T, T))) -> [T; 3] { /// // `tail` can't be destructured inline into `(b, c)`, /// // it must be destructured separately /// konst::destructure!{(a, tail) = tup} /// /// konst::destructure!{(b, c) = tail} /// /// [a, b, c] /// } /// /// #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] macro_rules! destructure { // braced struct struct ($($(@$is_path:tt)? ::)? $($path:ident)::+ $(,)?{$($braced:tt)*} $($rem:tt)*) => ( $crate::__destructure__braced_struct_prepare_fields! { {$($braced)*} ($($(@$is_path)? ::)? $($path)::*) path $($rem)* } ); // tuple struct ($($(@$is_path:tt)? ::)? $($path:ident)::+ $(,)? ($($tupled:tt)*) $($rem:tt)*) => ( $crate::__destructure__tuple_struct_field_names!{ ( ($($(@$is_path)? ::)? $($path)::+) path $($rem)* ) () ($($tupled)*) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) } ); // braced struct struct ($struct_path:path $(,)? {$($braced:tt)*} $($rem:tt)*) => ( $crate::__destructure__braced_struct_prepare_fields! { {$($braced)*} ($struct_path) type $($rem)* } ); // tuple struct ($struct_path:path, ($($tupled:tt)*) $($rem:tt)*) => ( $crate::__destructure__tuple_struct_field_names!{ ( ($struct_path) type $($rem)* ) () ($($tupled)*) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) } ); // tuple (() $(:$tuple_ty:ty)? = $val:expr) => ( let () $(: $tuple_ty)? = $val; ); (($($tupled:tt)*) $($rem:tt)*) => ( $crate::__destructure__tuple_field_names!{ ($($rem)*) () ($($tupled)*) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) } ); // array ([] $(:$array_ty:ty)? = $val:expr) => ( let [] $(: $array_ty)? = $val; ); ( [$( $pat:tt $(@ $dotdot:tt)? ),* $(,)?] $($rem:tt)* ) => ( $crate::__destructure_array__process_fields!{ [$( ($pat) ($($dotdot $dotdot)?) ,)*] $($rem)* } ); } #[doc(hidden)] #[macro_export] macro_rules! __destructure__braced_struct_prepare_fields { ( {$($field:tt $(: $pattern:pat)?),* $(,)?} $($rem:tt)* ) => { $crate::__destructure_struct!{ {$(($field) $field $(: $pattern)?,)*} $($rem)* } } } #[doc(hidden)] #[macro_export] macro_rules! __destructure__tuple_struct_field_names { (($($rem:tt)*) ($($patterns:tt)*) () ($($fnames:tt)*)) => { $crate::__destructure_struct!{ {$($patterns)*} $($rem)* } }; ($fixed:tt $prev_patterns:tt (.. $($next_pattern:tt)*) $fnames:tt) => { $crate::__::compile_error!{ "`..` patterns are not supported in top-level tuple struct patterns" } }; ( $fixed:tt ($($prev_patterns:tt)*) ($pattern:pat $(, $($next_pattern:tt)*)?) ($fname:tt $($next_fnames:tt)*) ) => { $crate::__destructure__tuple_struct_field_names!{ $fixed ($($prev_patterns)* ($fname) $fname:$pattern,) ($($($next_pattern)*)?) ($($next_fnames)*) } }; } #[doc(hidden)] #[macro_export] macro_rules! __destructure_struct { ( { /* no fields */ $(,)? } ($($struct_path:tt)*) $path_kind:ident $(:$struct_ty:ty)? = $val:expr ) => ( let $($struct_path)* {} $(: $struct_ty)? = $val; ); ( { $(($($_fa0:ident)? $($_fa1:literal)?) $field:tt $(: $pattern:pat)?),* $(,)? } ($($struct_path:tt)*) $path_kind:ident $(:$struct_ty:ty)? = $val:expr ) => ( // assert that `$struct_path` has precisely the fields that the user listed let val @ $($struct_path)* {$($field: _),*} $(: $struct_ty)? = $val; // asserts that `val` is not a reference, // protects against match ergonomics allowing `$val` to be a references. // // This always uses `$($struct_path)*`, even if `$struct_ty` is passed, // because: // - if this tested the type using `$struct_ty`, // it would allow passing a reference to a struct when `$struct_ty == &Struct`. // - `$($struct_path)*` is guaranteed to be a struct due to it being used // in the pattern above $crate::__destructuring__type_assert!{($path_kind $($struct_path)*) val} let mut val = $crate::__::ManuallyDrop::new(val); let ptr: *mut _ = $crate::macros::destructuring::cast_manuallydrop_ptr(&raw mut val); if false { _ = ||{ use $crate::macros::destructuring::__GetImplsHelper as _; // assert that the struct doesn't impl Drop // (its fields can, just not the struct itself) let assertion_expected: $crate::macros::destructuring::__DoesNotImplDrop<_> = if false { $crate::macros::destructuring::__DoesNotImplDrop::new(ptr) } else { let assertion = $crate::macros ::destructuring ::__GetImpls_IWRHQLPNNIEU8C6W( $crate::macros::destructuring::make_phantom(ptr) ).__impls_drop_iwrhqlpnnieu8c6w(); assertion }; }; } $( // SAFETY: the value being wrapped in a ManuallyDrop, // and the asserts above, ensure that these reads are safe. // // using `read_unaligned` to support destructuring packed structs let $crate::__first_pat!( $($pattern,)? $field, ) = unsafe { $crate::__::ptr::read_unaligned(&raw mut (*ptr).$field) }; )* ); ( { $(($($_fa0:ident)? $($_fa1:literal)?) $field0:tt $(: $_0:pat)? ,)* $( (..) $field1:tt $(: $_1:pat)? , $($__anything:tt)* )? } $($_3:tt)* ) => ( compile_error!{"`..` patterns are not supported in top-level struct patterns"} ) } #[doc(hidden)] #[macro_export] macro_rules! __destructuring__type_assert { ((path $($path:tt)*) $variable:ident) => { // assert that `$variable` is a struct, not a reference to a struct #[allow(unreachable_code)] if false { loop {} let expected @ $($path)* {..}; $crate::macros::destructuring::assert_same_type(expected, $variable) } }; ((type $type:ty) $variable:ident) => { let _: $type = $variable; }; } #[doc(hidden)] #[macro_export] macro_rules! __destructure__tuple_field_names { (($($rem:tt)*) ($($patterns:tt)*) () ($($fnames:tt)*)) => { $crate::__destructure_tuple!{($($patterns)*) $($rem)*} }; ($fixed:tt $prev_patterns:tt (.. $($next_pattern:tt)*) $fnames:tt) => { $crate::__::compile_error!{"`..` patterns are not supported in top-level tuple patterns"} }; ( $fixed:tt ($($prev_patterns:tt)*) ($pattern:pat $(, $($next_pattern:tt)*)?) ($fname:tt $($next_fnames:tt)*) ) => { $crate::__destructure__tuple_field_names!{ $fixed ($($prev_patterns)* $fname:$pattern,) ($($($next_pattern)*)?) ($($next_fnames)*) } }; } #[doc(hidden)] #[macro_export] macro_rules! __destructure_tuple { (($($field:tt: $pattern:pat,)*) $(:$tuple_ty:ty)? = $val:expr) => ( // assert that the tuple has precisely the element count that the user passed // // $tuple_ty being passed is not enough of an assertion, // because it might be a tuple with more elements, // so we construct a pattern to assert it. let val @ ($($crate::__first_pat!(_, $field),)*) : $crate::__first_ty!($($tuple_ty,)? ($($crate::__first_ty!(_, $field),)*),) = $val; // assert that `val` is a tuple, not a reference to a tuple #[allow(unreachable_code)] if false { loop {} let expected @ ($($crate::__first_pat!(_, $field),)*); $crate::macros::destructuring::assert_same_type(expected, val) } let mut val = $crate::__::ManuallyDrop::new(val); let ptr = $crate::macros::destructuring::cast_manuallydrop_ptr(&raw mut val); $( // SAFETY: the value being wrapped in a ManuallyDrop, // and the asserts above, ensure that these reads are safe. let $pattern = unsafe { $crate::__::ptr::read(&raw mut (*ptr).$field) }; )* ) } #[doc(hidden)] #[macro_export] macro_rules! __destructure_array__process_fields { ( [$( ( $( _ $($is_underscore:lifetime)? )? $( $ident:ident)? $( ($parenthesized:pat) )? $( .. $($has_rem_elems1:lifetime)? )? ) ($(.. $rem_elems:tt $($has_rem_elems2:lifetime)?)?), )*] $($rem:tt)* ) => { $crate::__destructure_array! { [$( ( ( $(rem $($has_rem_elems1)?)? $(rem $($has_rem_elems2)?)? elem ) $(_ $($is_underscore)?)? $(_ $($has_rem_elems1)?)? $( $ident )? $( $parenthesized )? ) )*] $($rem)* } } } #[doc(hidden)] #[macro_export] macro_rules! __destructure_array { ( [ $( ((elem $($__0:tt)*) $pat_prefix:tt) )* $( ((rem $($__1:tt)*) $pat_rem:tt) $( ((elem $($__2:tt)*) $pat_suffix:tt) )* )? ] $(:$array_ty:ty)? = $val:expr ) => { let array $(: $array_ty)? = $val; $( let $crate::__first_pat!(rem_ty_phantom, $pat_rem) = $crate::__::PhantomData; )? // asserts the length of the array, // and computes the length of the array produced by `@ ..` patterns #[allow(unreachable_code)] if false { loop {} // assert that `array` is an array, not a reference to an array _ = $crate::macros::destructuring::array_into_phantom(array); let [ $($crate::__first_pat!(_, $pat_prefix),)* $( $crate::__first_pat!(rem @ .., $pat_rem), $($crate::__first_pat!(_, $pat_suffix),)* )? ] = array; $( rem_ty_phantom = $crate::macros::destructuring::array_into_phantom( $crate::__first_expr!(rem, $pat_rem) ); )? } let mut array = $crate::macros::destructuring::__ArrayManuallyDrop::new(array); let ptr = $crate::macros::destructuring::cast_manuallydrop_array_ptr(&raw mut array); let mut i = 0; $crate::__destructure_array__read_elems!{unsafe, ptr, i, [$($pat_prefix),*]} $( // SAFETY: the array being wrapped in a ManuallyDrop, // and the assertions above, ensure that these reads are safe. let $pat_rem = unsafe { let rem_ptr = $crate::macros::destructuring::cast_ptr_with_phantom( <*mut _>::add(ptr, i), rem_ty_phantom, ); $crate::__::ptr::read(rem_ptr) }; i += $crate::macros::destructuring::get_phantom_len(rem_ty_phantom); $crate::__destructure_array__read_elems!{unsafe, ptr, i, [$($pat_suffix),*]} )? } } #[doc(hidden)] #[macro_export] macro_rules! __destructure_array__read_elems { ($unsafe:ident, $ptr:ident, $i:ident, [$($pattern:pat),*]) => { $( // SAFETY: the array being wrapped in a ManuallyDrop, // and the assertions above, ensure that these reads are safe. let $pattern = $unsafe { $crate::__::ptr::read(<*mut _>::add($ptr, $i)) }; $i += 1; )* } } #[macro_export] #[doc(hidden)] macro_rules! __first_pat { ($first:pat, $($rem:tt)* ) => { $first }; } #[macro_export] #[doc(hidden)] macro_rules! __first_ty { ($first:ty, $($rem:tt)* ) => { $first }; } #[macro_export] #[doc(hidden)] macro_rules! __first_expr { ($first:expr, $($rem:tt)* ) => { $first }; } konst-0.3.16/src/macros/impl_cmp.rs000064400000000000000000000136401046102023000152760ustar 00000000000000/// For implementing const comparison semi-manually. /// /// # Impls /// /// This macro implements [`ConstCmp`] for all the `impl`d types, /// and outputs the methods/associated constants in each of the listed impls. /// /// # Example /// /// ### Generic type /// /// This demonstrates how you can implement equality and ordering comparison for a generic struct. /// /// ```rust /// use konst::{const_cmp, const_eq, impl_cmp, try_equal}; /// /// use std::{ /// cmp::Ordering, /// marker::PhantomData, /// }; /// /// pub struct Tupled(u32, T); /// /// impl_cmp!{ /// impl[T] Tupled> /// where[ T: 'static ]; /// /// impl[] Tupled; /// impl Tupled>; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// const_eq!(self.0, other.0) && /// const_eq!(self.1, other.1) /// } /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// try_equal!(const_cmp!(self.0, other.0)); /// try_equal!(const_cmp!(self.1, other.1)) /// } /// } /// /// const _: () = { /// let foo = Tupled(3, PhantomData::); /// let bar = Tupled(5, PhantomData::); /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!( const_eq!(foo, foo)); /// /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(!const_eq!(foo, bar)); /// /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(!const_eq!(bar, foo)); /// /// assert!(matches!(const_cmp!(bar, bar), Ordering::Equal)); /// assert!( const_eq!(bar, bar)); /// }; /// ``` /// /// ### Enum /// /// This demonstrates how you can implement equality and ordering comparison for an enum. /// /// ```rust /// use konst::{const_cmp, const_eq, impl_cmp, try_equal}; /// /// use std::cmp::Ordering; /// /// pub enum Enum { /// Tupled(u32, u32), /// Unit, /// } /// /// impl_cmp!{ /// impl Enum; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// match (self, other) { /// (Self::Tupled(l0,l1), Self::Tupled(r0, r1)) => *l0 == *r0 && *l1 == *r1, /// (Self::Unit, Self::Unit) => true, /// _ => false, /// } /// } /// pub const fn const_cmp(&self, other: &Self) -> Ordering { /// match (self, other) { /// (Self::Tupled(l0,l1), Self::Tupled(r0, r1)) => { /// try_equal!(const_cmp!(*l0, *r0)); /// try_equal!(const_cmp!(*l1, *r1)) /// } /// (Self::Tupled{..}, Self::Unit) => Ordering::Less, /// (Self::Unit, Self::Unit) => Ordering::Equal, /// (Self::Unit, Self::Tupled{..}) => Ordering::Greater, /// } /// } /// } /// /// const _: () = { /// let foo = Enum::Tupled(3, 5); /// let bar = Enum::Unit; /// /// assert!(matches!(const_cmp!(foo, foo), Ordering::Equal)); /// assert!( const_eq!(foo, foo)); /// /// assert!(matches!(const_cmp!(foo, bar), Ordering::Less)); /// assert!(!const_eq!(foo, bar)); /// /// assert!(matches!(const_cmp!(bar, foo), Ordering::Greater)); /// assert!(!const_eq!(bar, foo)); /// /// assert!(matches!(const_cmp!(bar, bar), Ordering::Equal)); /// assert!( const_eq!(bar, bar)); /// }; /// /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp /// #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! impl_cmp { ( $($rem:tt)* ) => ( $crate::__impl_cmp_recursive!{ impls[ ] tokens[$($rem)*] } ); ( $($rem:tt)* ) => ( $crate::__impl_cmp_recursive!{ impls[ ] tokens[$($rem)*] } ); } #[doc(hidden)] #[macro_export] macro_rules! __impl_cmp_recursive{ ( impls[$($impls:tt)*] tokens[ $(#[$impl_attr:meta])* impl[$($impl_:tt)*] $type:ty $(where[ $($where:tt)* ])?; $($rem:tt)* ] ) => ( $crate::__impl_cmp_recursive!{ impls[ $($impls)* ( $(#[$impl_attr])* impl[$($impl_)*] $type where[ $($($where)*)? ]; ) ] tokens[ $($rem)* ] } ); // The same as the above macro branch, but it doesn't require the `[]` in `impl[]` ( impls[$($impls:tt)*] tokens[ $(#[$impl_attr:meta])* impl $type:ty $(where[ $($where:tt)* ])?; $($rem:tt)* ] ) => ( $crate::__impl_cmp_recursive!{ impls[ $($impls)* ( $(#[$impl_attr])* impl[] $type where[ $($($where)*)? ]; ) ] tokens[ $($rem)* ] } ); ( impls [ $( $an_impl:tt )+ ] tokens $stuff:tt ) => ( $( $crate::__impl_cmp_impl!{ $an_impl $stuff } )+ ); } #[doc(hidden)] #[macro_export] macro_rules! __impl_cmp_impl { ( ( $(#[$impl_attr:meta])* impl[$($impl_:tt)*] $type:ty where[ $($where:tt)* ]; ) [ $($everything:tt)* ] )=>{ $(#[$impl_attr])* impl<$($impl_)*> $crate::__::ConstCmp for $type where $($where)* { type Kind = $crate::__::IsNotStdKind; } $(#[$impl_attr])* impl<$($impl_)*> $type where $($where)* { $($everything)* } }; } #[doc(hidden)] #[macro_export] macro_rules! __impl_cmp_self_ty { ($self:ty, /*is_std_type*/ true )=>{ $crate::__::PWrapper<$self> }; ($self:ty, /*is_std_type*/ false )=>{ $self }; } konst-0.3.16/src/macros/minmax_macros.rs000064400000000000000000000176541046102023000163440ustar 00000000000000/// Const equivalent of [`std::cmp::min`](core::cmp::min) /// /// The arguments must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_eq` method taking a reference. /// /// Returns the `$left` argument if both compare equal. /// /// # Example /// /// ```rust /// const M: u32 = konst::min!(3u32, 5); /// assert_eq!(M, 3); /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! min { ($left:expr, $right:expr) => { match ($left, $right) { (left, right) => { if let $crate::__::Greater = $crate::const_cmp!(left, right) { right } else { left } } } }; } /// Const equivalent of [`std::cmp::max`](core::cmp::max) /// /// The arguments must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_eq` method taking a reference. /// /// Returns the `$right` argument if both compare equal. /// /// # Example /// /// ```rust /// const M: &str = konst::max!("world", "hello"); /// assert_eq!(M, "world"); /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! max { ($left:expr, $right:expr) => { match ($left, $right) { (left, right) => { if let $crate::__::Greater = $crate::const_cmp!(left, right) { left } else { right } } } }; } //////////////////////////////////////////////////////////////////////////////// /// Const equivalent of [`std::cmp::min_by`](core::cmp::min_by) /// /// Returns the `$left` argument if both compare equal. /// /// # Example /// /// ```rust /// // passing a pseudo-closure as the comparator /// const AAA: u32 = konst::min_by!(3u32, 10, |&l, &r| konst::const_cmp!(l, r / 4)); /// assert_eq!(AAA, 10); /// /// // Both arguments compare equal, so the first argument (`12`) is returned. /// const MIN_OF_EQ: u32 = konst::min_by!(12, 6, |l, r: &u32| konst::const_cmp!(*l % 3, *r % 3)); /// assert_eq!(MIN_OF_EQ, 12); /// /// const fn cmp_len(l: &str, r: &str) -> std::cmp::Ordering { /// konst::const_cmp!(l.len(), r.len()) /// } /// /// // passing a function as the comparator /// const BBB: &str = konst::min_by!("he", "bar", cmp_len); /// assert_eq!(BBB, "he"); /// ``` #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! min_by { ($left:expr, $right:expr, $($comparator:tt)*) => { $crate::__::__parse_closure_2!{ ($crate::__min_by) ($left, $right,) (min_by), $($comparator)* } }; } /// Const equivalent of [`std::cmp::max_by`](core::cmp::max_by) /// /// Returns the `$right` argument if both compare equal. /// /// # Example /// /// ```rust /// // passing a pseudo-closure as the comparator /// const AAA: u32 = konst::max_by!(3u32, 10, |&l, &r| konst::const_cmp!(l, r / 4)); /// assert_eq!(AAA, 3); /// /// // Both arguments compare equal, so the second argument (`6`) is returned. /// const MAX_OF_EQ: u32 = konst::max_by!(12, 6, |l: &u32, r| konst::const_cmp!(*l % 3, *r % 3)); /// assert_eq!(MAX_OF_EQ, 6); /// /// const fn cmp_len(l: &str, r: &str) -> std::cmp::Ordering { /// konst::const_cmp!(l.len(), r.len()) /// } /// /// // passing a function as the comparator /// const BBB: &str = konst::max_by!("he", "bar", cmp_len); /// assert_eq!(BBB, "bar"); /// ``` #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! max_by { ($left:expr, $right:expr, $($comparator:tt)*) => { $crate::__::__parse_closure_2!{ ($crate::__max_by) ($left, $right,) (max_by), $($comparator)* } }; } #[macro_export] #[doc(hidden)] macro_rules! __min_by { ( $left:expr, $right:expr, ($($closure_params:tt)*) $(-> $ret_ty:ty)? $ret_val:block ) => { match [$left, $right] { [left, right] => { let $($closure_params)* = (&left, &right); if let $crate::__::Greater = $ret_val { right } else { left } } } }; } #[macro_export] #[doc(hidden)] macro_rules! __max_by { ( $left:expr, $right:expr, ($($closure_params:tt)*) $(-> $ret_ty:ty)? $ret_val:block ) => { match [$left, $right] { [left, right] => { let $($closure_params)* = (&left, &right); if let $crate::__::Greater = $ret_val { left } else { right } } } }; } //////////////////////////////////////////////////////////////////////////////// /// Const equivalent of [`std::cmp::min_by_key`](core::cmp::min_by_key) /// /// The type returned by the comparator must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_eq` method taking a reference. /// /// Returns the `$left` argument if both compare equal. /// /// # Example /// /// ```rust /// // passing a pseudo-closure as the comparator /// const AAA: u32 = konst::min_by_key!(3u32, 10, |x| *x % 4); /// assert_eq!(AAA, 10); /// /// // Both arguments compare equal, so the first argument (`16`) is returned. /// const MIN_OF_EQ: u32 = konst::min_by_key!(16u32, 8, |x| *x % 4); /// assert_eq!(MIN_OF_EQ, 16); /// /// // passing a function as the comparator /// const BBB: &str = konst::min_by_key!("foo", "he", str::len); /// assert_eq!(BBB, "he"); /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! min_by_key { ($left:expr, $right:expr, $($comparator:tt)*) => { $crate::__::__parse_closure_1!{ ($crate::__minmax_by_key) ($left, $right, Greater,) (min_by_key), $($comparator)* } }; } /// Const equivalent of [`std::cmp::max_by_key`](core::cmp::max_by_key) /// /// The type returned by the comparator must implement the [`ConstCmp`] trait. /// Non-standard library types must define a `const_eq` method taking a reference. /// /// Returns the `$right` argument if both compare equal. /// /// # Example /// /// ```rust /// // passing a pseudo-closure as the comparator /// const AAA: u32 = konst::max_by_key!(3u32, 10, |x| *x % 4); /// assert_eq!(AAA, 3); /// /// // Both arguments compare equal, so the second argument (`6`) is returned. /// const MAX_OF_EQ: u32 = konst::max_by_key!(12, 6, |x: &u32| *x % 4); /// assert_eq!(MAX_OF_EQ, 6); /// /// // passing a function as the comparator /// const BBB: &str = konst::max_by_key!("he", "bar", str::len); /// assert_eq!(BBB, "bar"); /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! max_by_key { ($left:expr, $right:expr, $($comparator:tt)*) => { $crate::__::__parse_closure_1!{ ($crate::__minmax_by_key) ($right, $left, Less,) (max_by_key), $($comparator)* } }; } #[macro_export] #[doc(hidden)] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] macro_rules! __minmax_by_key { ( $left:expr, $right:expr, $ord:ident, ($($elem:tt)*) $(-> $ret_ty:ty)? $v:block ) => { match [$left, $right] { [left, right] => { let left_key = { let $($elem)* = &left; $v }; let right_key = { let $($elem)* = &right; $v }; if let $crate::__::$ord = $crate::const_cmp!(left_key, right_key) { right } else { left } } } }; } konst-0.3.16/src/macros/parser_method.rs000064400000000000000000000346021046102023000163330ustar 00000000000000/// Calls a `Parser` method with many alternative string literals. /// /// If any of the literals match, the parser is mutated accordingly, /// otherwise the parser is left untouched. /// /// # Syntax /// /// The general syntax for this macro is /// `parser_method!{ , => }` /// /// Where `` is an expression (of [`Parser`] type) that can be assigned into. /// /// Where `` is the name of one of the [`Parser`] methods usable in this macro: /// /// - [`find_skip`] and [`rfind_skip`]: /// use the match-like syntax, running the branch of the first pattern that matches. /// [example](#find-example) /// /// - [`strip_prefix`] and [`strip_suffix`]: /// use the match-like syntax, running the branch of the first pattern that matches. /// [example](#parsing-enum-example) /// /// - [`trim_start_matches`] and [`trim_end_matches`]: /// use the pattern-only syntax, trimming the string while any pattern matches. /// [example](#trimming-example) /// /// Where `` can be either of these, depending on the ``: /// /// - A match-like syntax: /// A comma separated sequence of ` => ` branches, /// the last branch must be `_ => `. /// /// - Just the patterns: ``. /// /// Where `` can be be any amount of `|`-separated string literals /// (`const`ants don't work here), or `_`. /// Note that passing a macro that expands to a literal doesn't work here, /// `concat` and `stringify` are special cased to work. /// /// [`find_skip`]: parsing/struct.Parser.html#method.find_skip /// [`rfind_skip`]: parsing/struct.Parser.html#method.rfind_skip /// [`strip_prefix`]: parsing/struct.Parser.html#method.strip_prefix /// [`strip_suffix`]: parsing/struct.Parser.html#method.strip_suffix /// [`trim_start_matches`]: parsing/struct.Parser.html#method.trim_start_matches /// [`trim_end_matches`]: parsing/struct.Parser.html#method.trim_end_matches /// /// /// # Example /// /// /// ### Parsing enum /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// parser_method, unwrap_ctx, /// }; /// /// #[derive(Debug, PartialEq)] /// enum Color { /// Red, /// Blue, /// Green, /// } /// /// impl Color { /// pub const fn try_parse(mut parser: Parser<'_>) -> ParseValueResult<'_, Color> { /// parser_method!{parser, strip_prefix; /// "Red"|"red" => Ok((Color::Red, parser)), /// "Blue"|"blue" => Ok((Color::Blue, parser)), /// "Green"|"green" => Ok((Color::Green, parser)), /// _ => Err(parser.into_other_error(&"could not parse Color")), /// } /// } /// } /// /// const COLORS: [Color; 4] = { /// let parser = Parser::new("BlueRedGreenGreen"); /// let (c0, parser) = unwrap_ctx!(Color::try_parse(parser)); /// let (c1, parser) = unwrap_ctx!(Color::try_parse(parser)); /// let (c2, parser) = unwrap_ctx!(Color::try_parse(parser)); /// let (c3, _ ) = unwrap_ctx!(Color::try_parse(parser)); /// /// [c0, c1, c2, c3] /// }; /// /// assert_eq!(COLORS, [Color::Blue, Color::Red, Color::Green, Color::Green]) /// /// /// ``` /// /// /// ### `find_skip` /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// parser_method, unwrap_ctx, /// }; /// /// { /// let mut parser = Parser::new("baz_foo_bar_foo"); /// /// fn find(parser: &mut Parser<'_>) -> u32 { /// let before = parser.remainder(); /// parser_method!{*parser, find_skip; /// "foo" => 0, /// "bar" => 1, /// "baz" => 2, /// _ => { /// assert_eq!(before, parser.remainder()); /// 3 /// } /// } /// } /// /// assert_eq!(find(&mut parser), 2); /// assert_eq!(parser.remainder(), "_foo_bar_foo"); /// /// assert_eq!(find(&mut parser), 0); /// assert_eq!(parser.remainder(), "_bar_foo"); /// /// assert_eq!(find(&mut parser), 1); /// assert_eq!(parser.remainder(), "_foo"); /// /// assert_eq!(find(&mut parser), 0); /// assert_eq!(parser.remainder(), ""); /// /// assert_eq!(find(&mut parser), 3); /// assert_eq!(parser.remainder(), ""); /// } /// { /// let mut parser = Parser::new("foo_bar_foo_baz"); /// /// fn rfind(parser: &mut Parser<'_>) -> u32 { /// parser_method!{*parser, rfind_skip; /// "foo" => 0, /// "bar" => 1, /// "baz" => 2, /// _ => 3, /// } /// } /// /// assert_eq!(rfind(&mut parser), 2); /// assert_eq!(parser.remainder(), "foo_bar_foo_"); /// /// assert_eq!(rfind(&mut parser), 0); /// assert_eq!(parser.remainder(), "foo_bar_"); /// /// assert_eq!(rfind(&mut parser), 1); /// assert_eq!(parser.remainder(), "foo_"); /// /// assert_eq!(rfind(&mut parser), 0); /// assert_eq!(parser.remainder(), ""); /// /// assert_eq!(rfind(&mut parser), 3); /// assert_eq!(parser.remainder(), ""); /// } /// /// /// /// ``` /// /// /// ### Trimming /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// parser_method, unwrap_ctx, /// }; /// /// { /// let mut parser = Parser::new("foobarhellofoobar"); /// parser_method!{parser, trim_start_matches; "foo" | "bar" } /// assert_eq!(parser.remainder(), "hellofoobar"); /// } /// { /// let mut parser = Parser::new("foobarhellofoobar"); /// parser_method!{parser, trim_end_matches; "foo" | "bar" } /// assert_eq!(parser.remainder(), "foobarhello"); /// } /// { /// let mut parser = Parser::new("foobar"); /// // Empty string literals make trimming finish when the previous patterns didn't match, /// // so the "bar" pattern doesn't do anything here /// parser_method!{parser, trim_start_matches; "foo" | "" | "bar" } /// assert_eq!(parser.remainder(), "bar"); /// } /// ``` /// /// [`Parser`]: parsing/struct.Parser.html #[cfg(feature = "parsing_proc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing_proc")))] #[macro_export] macro_rules! parser_method { ($place:expr, find_skip; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromStart, __priv_pa_find_skip, outside_konst) () $($branches)* } }; ($place:expr, rfind_skip; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromEnd, __priv_pa_rfind_skip, outside_konst) () $($branches)* } }; ($place:expr, strip_prefix; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromStart, __priv_pa_strip_prefix, outside_konst) () $($branches)* } }; ($place:expr, strip_suffix; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromEnd, __priv_pa_strip_suffix, outside_konst) () $($branches)* } }; ($place:expr, trim_start_matches; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromStart, __priv_pa_trim_start_matches, outside_konst) () $($branches)* } }; ($place:expr, trim_end_matches; $($branches:tt)* ) => { $crate::__priv_pa_normalize_branches!{ ($place, FromEnd, __priv_pa_trim_end_matches, outside_konst) () $($branches)* } }; ($place:expr, $unknown_method:ident; $($branches:tt)* ) => { $crate::__::compile_error!{"\ Expected the second argument (the name of the Parser method) to be one of: \n\ - find_skip \n\ - rfind_skip \n\ - strip_prefix \n\ - strip_suffix \n\ - trim_start_matches \n\ - trim_end_matches \n\ "} }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_normalize_branches { // Parsing just pattens ( ($place:expr, $parse_direction:ident, $method_macro:ident, $call_place:tt) () $($pattern:pat_param)|* ) => { $crate::$method_macro!{ ($place, $parse_direction, $call_place) $($pattern)|* } }; // Parsing match like syntax ( ($place:expr, $parse_direction:ident, $method_macro:ident, $call_place:tt) ( $($branches:tt)* ) _ => $expr:expr // Nothing left to parse $(, $($rem:tt)*)? ) => {{ $crate::__priv_no_tokens_after_last_branch!{$($($rem)*)?} $crate::$method_macro!{ ($place, $parse_direction, $call_place) $($branches)* default => ($expr) } }}; ( $fixed_params:tt ( $($prev_branch:tt)* ) $($pattern:pat_param)|* => $expr:expr, $($rem:tt)* ) => {{ $crate::__priv_tokens_after_middle_branch!{$($rem)*} $crate::__priv_pa_normalize_branches!{ $fixed_params ( $($prev_branch)* ($($pattern)|*) => ($expr) ) $($rem)* } }}; ( $fixed_params:tt ( $($prev_branch:tt)* ) $($pattern:pat_param)|* => $expr:block $($rem:tt)* ) => {{ $crate::__priv_tokens_after_middle_branch!{$($rem)*} $crate::__priv_pa_normalize_branches!{ $fixed_params ( $($prev_branch)* ($($pattern)|*) => ($expr) ) $($rem)* } }}; } ////////////////////////////////////////////////////////////////////////////////// #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_find_skip { ( $($args:tt)* ) => {{ $crate::__priv_pa_find_skip_either!{ brem, [_, brem @ ..], __priv_bstr_start, $($args)* } }}; } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_rfind_skip { ( $($args:tt)* ) => {{ $crate::__priv_pa_find_skip_either!{ brem, [brem @ .., _], __priv_bstr_end, $($args)* } }}; } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_find_skip_either { ( $brem:ident, $split_first_pat:pat_param, $pat_proc_macro:ident, $accessor_args:tt $( ($($pattern:pat_param)|*)=>($e:expr) )* default => ($default:expr) ) => {{ let mut bytes = $crate::__priv_pa_bytes_accessor!(get, $accessor_args); loop { match bytes { $( $( $crate::$pat_proc_macro!(rem, $pattern))|* => { $crate::__priv_pa_bytes_accessor!(set, $accessor_args, rem); break $e } )* _ => { if let $split_first_pat = bytes { bytes = $brem; } else { break $default; } } } } }} } ////////////////////////////////////////////////////////////////////////////////// #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_strip_prefix { ( $accessor_args:tt $( ($($pattern:pat_param)|*)=>($e:expr) )* default => $default:expr ) => { match $crate::__priv_pa_bytes_accessor!(get, $accessor_args) { $( $( $crate::__priv_bstr_start!(rem, $pattern))|* => { $crate::__priv_pa_bytes_accessor!(set, $accessor_args, rem); $e } )* _ => $default, } }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_strip_suffix { ( $accessor_args:tt $( ($($pattern:pat_param)|*)=>($e:expr) )* default => ($default:expr) ) => { match $crate::__priv_pa_bytes_accessor!(get, $accessor_args) { $( $( $crate::__priv_bstr_end!(rem, $pattern))|* => { $crate::__priv_pa_bytes_accessor!(set, $accessor_args, rem); $e } )* _ => $default, } }; } ////////////////////////////////////////////////////////////////////////////////// #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_trim_start_matches { ( $($args:tt)* ) => { $crate::__priv_pa_trim_matches_inner!{__priv_bstr_start $($args)*} } } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_trim_end_matches { ( $($args:tt)* ) => { $crate::__priv_pa_trim_matches_inner!{__priv_bstr_end $($args)*} } } #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_trim_matches_inner{ ( $pat_proc_macro:ident $accessor_args:tt $($pattern:pat_param)|* ) => {{ let mut bytes = $crate::__priv_pa_bytes_accessor!(get, $accessor_args); while let $( $crate::$pat_proc_macro!(rem, $pattern) )|* = bytes { if rem.len() == bytes.len() { break } else { bytes = rem; } } $crate::__priv_pa_bytes_accessor!(set, $accessor_args, bytes); }} } ////////////////////////////////////////////////////////////////////////////////// #[doc(hidden)] #[macro_export] macro_rules! __priv_pa_bytes_accessor { (get, ($place:expr, $parse_direction:ident, outside_konst)) => { $place.remainder().as_bytes() }; (set, ($place:expr, FromStart, outside_konst), $rem:expr) => { #[allow(unused_assignments)] { $place = $place.skip($place.remainder().len() - $rem.len()); } }; (set, ($place:expr, FromEnd, outside_konst), $rem:expr) => { #[allow(unused_assignments)] { $place = $place.skip_back($place.remainder().len() - $rem.len()); } }; } ////////////////////////////////////////////////////////////////////////////////// #[doc(hidden)] #[macro_export] macro_rules! __priv_no_tokens_after_last_branch { () => {}; ($($tokens:tt)+) => { compile_error! {"expected no branches after the first `_ => ` branch"} }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_tokens_after_middle_branch { () => { compile_error! {"expected more branches, ending with a `_ => ` branch"} }; ($($tokens:tt)+) => {}; } konst-0.3.16/src/macros/parsing_macros.rs000064400000000000000000000207321046102023000165050ustar 00000000000000/// Like an `if let Ok`, /// but also reassigns variables with the value in the `Ok` variant. /// /// Note: the `Ok` variant can only be destructured into a single variable or a tuple. /// /// # Let pattern /// /// You can declare variables usable inside this macro with `let` patterns, like this: /// ```rust /// # use konst::rebind_if_ok; /// # /// # let mut bar = 0; /// # let mut number = 10; /// let res: Result<_, ()> = Ok((10, 20)); /// rebind_if_ok!{(let foo, bar) = res => /// number += foo; /// } /// # assert_eq!(bar, 20); /// ``` /// `foo` in this invocation of `rebind_if_ok` is a macro-local variable initialized with `10`, /// while `bar` is a pre-existing variable that is assigned `20`. /// /// This pattern only works when destructuring tuples. /// /// # Example /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// rebind_if_ok, /// }; /// /// #[derive(Debug, PartialEq)] /// struct Struct { /// foo: bool, /// bar: bool, /// baz: Option, /// } /// /// const fn parse_struct(mut parser: Parser<'_>) -> (Struct, Parser<'_>) { /// let mut flags = Struct { /// foo: false, /// bar: false, /// baz: None, /// }; /// /// // `parser` is reassigned if the `strip_prefix` method returns an `Ok` variant. /// // (this also happens in every other invocation of `rebind_if_ok` in this example) /// rebind_if_ok!{parser = parser.strip_prefix("foo,") => /// flags.foo = true; /// } /// rebind_if_ok!{parser = parser.strip_prefix("bar,") => /// flags.bar = true; /// } /// // `num` is only visible inside this macro invocation /// rebind_if_ok!{(let num, parser) = parser.parse_u64() => /// flags.baz = Some(num); /// } /// (flags, parser) /// } /// /// const XX: [Struct; 2] = { /// [ /// parse_struct(Parser::new("foo,1000")).0, /// parse_struct(Parser::new("bar,")).0, /// ] /// }; /// /// assert_eq!( /// XX, /// [ /// Struct{foo: true, bar: false, baz: Some(1000)}, /// Struct{foo: false, bar: true, baz: None}, /// ] /// ); /// /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] #[macro_export] macro_rules! rebind_if_ok { ( $pattern:tt $(:$ty:ty)? = $expression:expr $( => $($code:tt)* )? ) => { if let $crate::__::v::Ok(tuple) = $expression { $crate::__priv_ai_preprocess_pattern!{tuple, ($pattern $(:$ty)?)} $($($code)*)? } }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_ai_preprocess_pattern { ( $var:ident, (($($pat:tt)*))) => { $crate::__priv_assign_tuple!{$var, (0 1 2 3 4 5) , $($pat)*} }; ( $var:ident, ($($pat:tt)*)) => { $crate::__priv_assign_tuple!{$var, (0 1 2 3 4 5) , $($pat)*} }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_assign_tuple { ($var:ident, $fields:tt, let $pat:tt: $ty:ty $(, $($rem:tt)*)?) => { $crate::__priv_next_ai_access!{ (let $pat: $ty) $var, $fields, $($($rem)*)? } }; ($var:ident, $fields:tt, let $pat:pat_param $(, $($rem:tt)*)?) => { $crate::__priv_next_ai_access!{ (let $pat) $var, $fields, $($($rem)*)? } }; ($var:ident, $fields:tt, _ $(: $ty:ty)? $(, $($rem:tt)*)?) => { $crate::__priv_next_ai_access!{ (let _ $(: $ty)? ) $var, $fields, $($($rem)*)? } }; ($var:ident, $fields:tt, $e:tt $(: $ty:ty)? $(, $($rem:tt)*)?) => { $(let _: $ty = $var;)? $crate::__priv_next_ai_access!{ ($e) $var, $fields, $($($rem)*)? } }; ($var:ident, $fields:tt, $e:expr $(, $($rem:tt)*)?) => { $crate::__priv_next_ai_access!( ($e) $var, $fields, $($($rem)*)? ) }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_next_ai_access { ( ($($lhs:tt)*) $var:ident , (0 $($rem_fields:tt)*), ) => { $($lhs)* = $var; }; ( ($($lhs:tt)*) $var:ident , ($field:tt $($rem_fields:tt)*), ) => { $($lhs)* = $var.$field; }; ( ($($lhs:tt)*) $var:ident , ($field:tt $($rem_fields:tt)*), $($rem:tt)+ ) => { $($lhs)* = $var.$field; $crate::__priv_assign_tuple!($var,($($rem_fields:tt)*), $($rem)+) }; } /////////////////////////////////////////////////////////////////////////////// /// Like the `?` operator, /// but also reassigns variables with the value in the `Ok` variant. /// /// Note: the `Ok` variant can only be destructured into a single variable or a tuple. /// /// # Let pattern /// /// You can declare new variables with `let` patterns like this: /// ```text /// try_rebind!{(let foo, bar) = Ok((10, 20))} /// try_rebind!{(let (a, b, c), bar) = Ok(((10, 10, 10), 20))} /// ``` /// `foo` in here is a new variable initialized with `10` (same for `a`, `b`, and `c`), /// while `bar` is a pre-existing variable that is assigned `20`. /// /// This pattern only works when destructuring tuples. /// /// # Examples /// /// ### Parsing /// /// Inside of `parse_int_pair`, `parser` always refers to the same variable. /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// try_rebind, unwrap_ctx, /// }; /// /// const fn parse_int_pair(mut parser: Parser<'_>) -> ParseValueResult<'_, (u64, u64)> { /// /// // `parser` is reassigned if the `parse_u64` method returns an `Ok`. /// // (this also happens in every other invocation of `try_rebind` in this example) /// try_rebind!{(let aa, parser) = parser.parse_u64()} /// /// try_rebind!{parser = parser.strip_prefix(',')} /// /// try_rebind!{(let bb, parser) = parser.parse_u64()} /// /// Ok(((aa, bb), parser)) /// } /// /// const PAIR: (u64, u64) = { /// let parser = Parser::new("100,200"); /// unwrap_ctx!(parse_int_pair(parser)).0 /// }; /// /// assert_eq!(PAIR, (100, 200)); /// /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] #[macro_export] macro_rules! try_rebind { ( $pattern:tt = $expression:expr $(,)? ) => { let tuple = match $expression { $crate::__::v::Ok(tuple) => tuple, $crate::__::v::Err(_e) => return $crate::__::v::Err(_e), }; $crate::__priv_ai_preprocess_pattern!(tuple, ($pattern)); }; } /////////////////////////////////////////////////////////////////////////////// macro_rules! partial{ ( $new_macro:ident = $macro:ident ! ($($prefix:tt)*) ) => { __priv_partial!( ($) $new_macro = $macro ! ($($prefix)*) ) }; } macro_rules! __priv_partial { ( ($_:tt) $new_macro:ident = $macro:ident ! ($($prefix:tt)*) ) => { macro_rules! $new_macro { ($_($_ args:tt)*) => { $macro!($($prefix)* $_($_ args)* ) } } } } /////////////////////////////////////////////////////////////////////////////// macro_rules! try_parsing { ( $parser:ident, $parse_direction:ident $(,$ret:ident)*; $($code:tt)* ) => ({ #![allow(unused_parens, unused_labels, unused_macros)] $parser.parse_direction = ParseDirection::$parse_direction; let copy = $parser; let ($($ret),*) = 'ret: { partial!{throw = throw_out!(copy, $parse_direction,)} #[allow(unreachable_code)] { $($code)* } }; enable_if_start!{$parse_direction, $parser.start_offset += (copy.str.len() - $parser.str.len()) as u32; } Ok(($($ret,)* $parser)) }) } macro_rules! parsing { ( $parser:ident, $parse_direction:ident $(,$ret:ident)*; $($code:tt)* ) => ({ #![allow(unused_parens, unused_labels, unused_macros)] $parser.parse_direction = ParseDirection::$parse_direction; enable_if_start!{$parse_direction, let copy = $parser; } let ($($ret),*) = { $($code)* }; enable_if_start!{$parse_direction, $parser.start_offset += (copy.str.len() - $parser.str.len()) as u32; } ($($ret,)* $parser) }) } macro_rules! throw_out { ($copy:ident, $parse_direction:ident, $kind:expr) => { return Err(crate::parsing::ParseError::new($copy, $kind)) }; ($copy:ident, $parse_direction:ident, $kind:expr, map_err = $func:ident) => { return Err($func(crate::parsing::ParseError::new($copy, $kind))) }; } macro_rules! enable_if_start{ (FromEnd, $($tokens:tt)*) => { }; (FromStart, $($tokens:tt)*) => { $($tokens)* }; (FromBoth, $($tokens:tt)*) => { $($tokens)* }; } konst-0.3.16/src/macros/parsing_polymorphism_macros.rs000064400000000000000000000041521046102023000213250ustar 00000000000000/// Parses a type that impls [`HasParser`] with the passed in [`Parser`]. /// /// # Example /// /// This example demonstrates how you can use this macro to parse both /// standard library and user-defined types. /// /// ```rust /// use konst::{parse_with, try_rebind, unwrap_ctx}; /// /// use konst::parsing::{HasParser, Parser, ParseValueResult}; /// /// const PAIR: (u32, Foo) = unwrap_ctx!(parse_pair(Parser::new("100,Baz"))).0; /// /// assert_eq!(PAIR.0, 100); /// assert_eq!(PAIR.1, Foo::Baz); /// /// const fn parse_pair(mut parser: Parser<'_>) -> ParseValueResult<'_, (u32, Foo)> { /// try_rebind!{(let left, parser) = parse_with!(parser, u32)} /// try_rebind!{parser = parser.strip_prefix(',')} /// try_rebind!{(let right, parser) = parse_with!(parser, Foo)} /// /// Ok(((left, right), parser)) /// } /// /// /// #[derive(Debug, PartialEq)] /// enum Foo { /// Bar, /// Baz, /// Qux, /// } /// /// impl HasParser for Foo { /// type Parser = Self; /// } /// /// impl Foo { /// const fn parse_with(parser: Parser<'_>) -> ParseValueResult<'_, Self> { /// // You can use the `parser_method` macro instead of this chain of if elses /// if let Ok(parser) = parser.strip_prefix("Bar") { /// Ok((Foo::Bar, parser)) /// } else if let Ok(parser) = parser.strip_prefix("Baz") { /// Ok((Foo::Baz, parser)) /// } else if let Ok(parser) = parser.strip_prefix("Qux") { /// Ok((Foo::Qux, parser)) /// } else { /// Err(parser.into_other_error(&"expected one of `Bar`, `Baz`, or `Qux`")) /// } /// } /// } /// ``` /// /// [`Parser`]: ./parsing/struct.Parser.html /// [`HasParser`]: ./parsing/trait.HasParser.html #[macro_export] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] macro_rules! parse_with { ($parser:expr, $type:ty $(,)*) => { match $parser { parser @ $crate::Parser { .. } => { let res: $crate::__::Result<_, _> = <<$type as $crate::parsing::HasParser>::Parser>::parse_with(parser); res } } }; } konst-0.3.16/src/macros/polymorphism_macros.rs000064400000000000000000000154431046102023000176070ustar 00000000000000#[doc(hidden)] #[macro_export] macro_rules! __priv_delegate_const_inner_fn{ ( $(skip_coerce $(@$_skip:tt@)?;)? $(for[$($implg:tt)*])? $(#[$attr:meta])* pub const fn $func:ident $(<$($fnlt:lifetime),* $(,)?>)?( $($idents:ident)* : $l_ty:ty, $rhs:ident: $r_ty:ty $(,)* ) -> $ret:ty $block:block )=>{ $(#[$attr])* pub const fn $func<$($($fnlt,)*)? $($($implg)*)?>( $crate::__priv_get_pati_ident!($($idents)*): $l_ty, $rhs: $r_ty, ) -> $ret $block } } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __priv_delegate_const_inner_cmpwrapper{ ( ($docs:expr, $cw_method:ident, $returns:ty) $(skip_coerce $(@$_skip:tt@)?;)* $( for[$($implg:tt)*] )? $(#[$attr:meta])* pub const fn $func:ident $(<$($fnlt:lifetime),* $(,)?>)?( $($idents:ident)* : $l_ty:ty, $rhs:ident: $r_ty:ty $(,)* ) -> $ret:ty $block:block ) => { $crate::__priv_std_kind_impl!{ $(skip_coerce $(@$_skip@)?;)* impl[$($($implg)*)?] $l_ty } impl<$($($implg)*)?> $crate::__::CmpWrapper<$l_ty> { #[doc = $docs] #[inline] pub const fn $cw_method<$($($fnlt,)*)?>( &self, other: $crate::__priv_ref_if_nonref!(($($idents)*) $r_ty), ) -> $returns { $func( $crate::__priv_copy_if_nonref!(($($idents)*) self.0), $crate::__priv_deref_if_nonref!(($($idents)*) other) ) } } } } /// `__delegate_const_eq` allows: /// - defining a free function, /// - defining an inherent `cosnt_eq` method on CmpWrapper that delegates to that free function. /// - ConstCmp impl for the first parameter type /// - Add a coerce inhenrent method for IsAConstCmp /// #[cfg(not(feature = "cmp"))] #[doc(hidden)] #[macro_export] macro_rules! __delegate_const_eq{ ( $($input:tt)* )=>{ $crate::__priv_delegate_const_inner_fn!{ $($input)* } } } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __delegate_const_eq{ ( $($input:tt)* )=>{ $crate::__priv_delegate_const_inner_fn!{ $($input)* } $crate::__priv_delegate_const_inner_cmpwrapper!{ ( "Compares `self` and `other` for equality.", const_eq, bool ) $($input)* } }; } #[cfg(not(feature = "cmp"))] #[doc(hidden)] #[macro_export] macro_rules! __delegate_const_ord{ ($($input:tt)*)=>{ $crate::__priv_delegate_const_inner_fn!{ $($input)* } } } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __delegate_const_ord{ ( $($input:tt)* )=>{ $crate::__priv_delegate_const_inner_fn!{ $($input)* } $crate::__priv_delegate_const_inner_cmpwrapper!{ ( "Compares `self` and `other` for ordering.", const_cmp, $crate::__::Ordering ) skip_coerce; $($input)* } }; } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __priv_copy_if_nonref { ((ref $ident:ident) $expr:expr) => { &$expr }; ((copy $ident:ident) $expr:expr) => { $expr }; } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __priv_deref_if_nonref { ((ref $ident:ident) $expr:expr) => { $expr }; ((copy $ident:ident) $expr:expr) => { *$expr }; } #[cfg(feature = "cmp")] #[doc(hidden)] #[macro_export] macro_rules! __priv_ref_if_nonref { ((ref $ident:ident) $ty:ty) => { $ty }; ((copy $ident:ident) $ty:ty) => { &$ty }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_get_pati_ident { (ref $ident:ident) => { $ident }; (copy $ident:ident) => { $ident }; } #[doc(hidden)] #[macro_export] macro_rules! __priv_std_kind_impl { ( impl[$($impl:tt)*] $self:ty $(where[ $($where_:tt)* ])? )=>{ impl<$($impl)*> $crate::__::ConstCmp for $self where $($($where_)*)? { type Kind = $crate::__::IsStdKind; } impl<$($impl)* __T> $crate::__::IsAConstCmp<$crate::__::IsStdKind, $self, __T> where $($($where_)*)? { /// #[inline(always)] pub const fn coerce(self, reference: &$self) -> $crate::__::CmpWrapper<$self> { $crate::__::CmpWrapper(*reference) } } }; (skip_coerce $($anything:tt)*)=>{}; } /// Coerces `reference` to a type that has a `const_eq` or `const_cmp` method. /// /// # Behavior /// /// This requires arguments to implement the [`ConstCmp`] trait. /// /// When a type from the standard library is passed, /// this wraps it inside a [`CmpWrapper`], /// which declares `const_eq` and `const_cmp` methods for many standard library types. /// /// When a user-defined type is used, this evaluates to a reference to the passed in value, /// dereferencing it as necessary. /// /// # Limitations /// /// The parameter(s) must be concrete types, and have a fully inferred type. /// eg: if you pass an integer literal it must have a suffix to indicate its type. /// /// # Example /// /// ```rust /// use konst::{ /// cmp::CmpWrapper, /// coerce_to_cmp, impl_cmp, /// }; /// /// struct Unit; /// /// impl_cmp!{ /// impl Unit; /// /// pub const fn const_eq(&self, other: &Self) -> bool { /// true /// } /// } /// /// let wrapper: CmpWrapper = coerce_to_cmp!(0i32); /// assert!( wrapper.const_eq(&0)); /// assert!(!wrapper.const_eq(&1)); /// /// let unit: &Unit = coerce_to_cmp!(Unit); /// assert!( unit.const_eq(&Unit)); /// /// /// /// /// /// /// ``` /// /// [`ConstCmp`]: crate::cmp::ConstCmp /// [`CmpWrapper`]: crate::cmp::CmpWrapper /// #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] #[macro_export] macro_rules! coerce_to_cmp { ($reference:expr $(,)*) => {{ match $reference { ref reference => { let marker = $crate::__::IsAConstCmp::NEW; if false { marker.infer_type(reference); } marker.coerce(reference) } } }}; ($left:expr, $right:expr $(,)*) => {{ match (&$left, &$right) { (left, right) => { let l_marker = $crate::__::IsAConstCmp::NEW; let r_marker = $crate::__::IsAConstCmp::NEW; if false { l_marker.infer_type(left); r_marker.infer_type(right); } (l_marker.coerce(left), r_marker.unreference(right)) } } }}; } konst-0.3.16/src/macros/unwrapping.rs000064400000000000000000000072251046102023000156720ustar 00000000000000/// `?`-like macro, which allows optionally mapping errors. /// /// `?` currently doesn't work in `const fn`s because as of Rust 1.65.0 /// trait methods don't work in `const fn`s. /// /// # Examples /// /// ### Basic /// /// ```rust /// use konst::try_; /// /// const OK: Result<&str, u8> = expect_no_whitespace("hello"); /// assert_eq!(OK, Ok("hello")); /// /// const ERR: Result<&str, u8> = expect_no_whitespace("hello world"); /// assert_eq!(ERR, Err(b' ')); /// /// /// const fn expect_no_whitespace(string: &str) -> Result<&str, u8> { /// let bytes = string.as_bytes(); /// konst::for_range!{i in 0..bytes.len() => /// try_!(assert_not_whitespace(bytes[i])); /// } /// Ok(string) /// } /// /// const fn assert_not_whitespace(byte: u8) -> Result<(), u8> { /// if matches!(byte, b'\t' | b'\n' | b'\r' | b' ') { /// Err(byte) /// } else { /// Ok(()) /// } /// } /// /// ``` /// /// ### Mapping errors /// /// ```rust /// use konst::try_; /// /// const EVENS: Result<[Even; 4], u32> = /// array_to_even([0, 2, 4, 6]); /// /// let new = |n| Even::new(n).unwrap(); /// assert_eq!(EVENS, Ok([new(0), new(2), new(4), new(6)])); /// /// /// const UNEVEN: Result<[Even; 4], u32> = /// array_to_even([0, 2, 5, 6]); /// /// assert_eq!(UNEVEN, Err(5)); /// /// /// const fn array_to_even(arr: [u32; 4]) -> Result<[Even; 4], u32> { /// let mut ret = [Even::ZERO; 4]; /// /// konst::for_range!{i in 0..4 => /// ret[i] = try_!(Even::new(arr[i]), map_err = |e| e.get() ); /// } /// /// Ok(ret) /// } /// /// #[derive(Debug, PartialEq)] /// pub struct Even(u32); /// /// impl Even { /// const ZERO: Even = Even(0); /// /// pub const fn new(number: u32) -> Result { /// if number % 2 == 0 { /// Ok(Even(number)) /// } else { /// Err(NotEven(number)) /// } /// } /// } /// /// #[derive(Debug, PartialEq)] /// pub struct NotEven(u32); /// /// impl NotEven { /// pub const fn get(&self) -> u32 { /// self.0 /// } /// } /// /// use std::fmt::{self, Display}; /// /// impl Display for NotEven { /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { /// fmt::Debug::fmt(self, f) /// } /// } /// /// impl std::error::Error for NotEven {} /// /// ``` /// #[macro_export] macro_rules! try_ { ($e:expr, map_err = |$($pati:pat_param)?| $v:expr $(,)*) => { match $e { $crate::__::Ok(x) => x, $crate::__::Err{$(0: $pati,)? ..} => return $crate::__::Err($v), } }; ($e:expr $(,)*) => {{ match $e { $crate::__::Ok(x) => x, $crate::__::Err(e) => return $crate::__::Err(e), } }}; } /// `?`-like macro for `Option`s. /// /// # Example /// /// ```rust /// use konst::try_opt; /// /// const SOME: Option = sum_u8s(&[3, 5, 8, 13]); /// assert_eq!(SOME, Some(29)); /// /// const NONE: Option = sum_u8s(&[3, 5, 8, 13, 240]); /// assert_eq!(NONE, None); /// /// const fn sum_u8s(mut nums: &[u8]) -> Option { /// let mut sum = 0_u8; /// while let [first, rem @ ..] = nums { /// nums = rem; /// # sum = try_opt!(checked_add(sum, *first)); /// # /* /// sum = try_opt!(sum.checked_add(*first)); /// # */ /// } /// Some(sum) /// } /// /// # const fn checked_add(l: u8, r: u8) -> Option { /// # let (res, overflowed) = l.overflowing_add(r); /// # if overflowed { None } else { Some(res) } /// # } /// ``` /// #[macro_export] macro_rules! try_opt { ($opt:expr $(,)*) => { match $opt { $crate::__::Some(x) => x, $crate::__::None => return $crate::__::None, } }; } konst-0.3.16/src/macros.rs000064400000000000000000000013151046102023000134720ustar 00000000000000#[cfg(feature = "cmp")] mod assert_cmp_macros; #[macro_use] mod const_eq_macros; #[macro_use] mod const_ord_macros; #[cfg(feature = "cmp")] #[macro_use] mod minmax_macros; #[macro_use] mod control_flow; #[macro_use] #[doc(hidden)] #[cfg(feature = "rust_1_83")] pub mod destructuring; #[macro_use] mod declare_cmp_fn_macros; #[macro_use] mod bytes_fn_macros; #[macro_use] mod declare_generic_const; #[macro_use] mod polymorphism_macros; #[cfg(feature = "parsing_proc")] #[macro_use] mod parser_method; #[cfg(feature = "parsing")] #[macro_use] mod parsing_macros; #[cfg(feature = "parsing")] #[macro_use] mod parsing_polymorphism_macros; #[macro_use] mod impl_cmp; #[macro_use] pub(crate) mod unwrapping; konst-0.3.16/src/manually_drop.rs000064400000000000000000000045521046102023000150620ustar 00000000000000//! Const fn equivalents of [`ManuallyDrop`](core::mem::ManuallyDrop) methods. use core::mem::ManuallyDrop; /// Const equivalent of `&*manually_drop` /// /// # Example /// /// ```rust /// use std::mem::ManuallyDrop; /// use konst::manually_drop; /// /// const FOO: &Foo = &Foo::new(123456); /// const FOO_REF: &u64 = FOO.get(); /// assert_eq!(FOO.get(), &123456); /// assert_eq!(FOO_REF, &123456); /// /// const MD: &ManuallyDrop = &ManuallyDrop::new(654321); /// assert_eq!(manually_drop::as_inner(MD), &654321); /// /// pub struct Foo(ManuallyDrop); /// /// impl Foo { /// pub const fn new(value: T) -> Self { /// Self(ManuallyDrop::new(value)) /// } /// /// pub const fn get(&self) -> &T { /// manually_drop::as_inner(&self.0) /// } /// } /// ``` #[inline(always)] pub const fn as_inner(md: &ManuallyDrop) -> &T { // SAFETY: ManuallyDrop is represented the same as T, // so their pointers should be compatible with an `as` cast unsafe { &*(md as *const ManuallyDrop as *const T) } } /// Const equivalent of `&mut *manually_drop` /// /// # Example /// /// ```rust /// use std::mem::ManuallyDrop; /// use konst::manually_drop; /// /// const fn add_100(num: &mut u32 ) { /// *num += 100; /// } /// /// const FOO: ManuallyDrop = { /// let mut mu = ManuallyDrop::new(5); /// let inner = manually_drop::as_inner_mut(&mut mu); /// add_100(inner); /// add_100(inner); /// add_100(inner); /// mu /// }; /// /// assert_eq!(*FOO, 305); /// ``` #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[inline(always)] pub const fn as_inner_mut(md: &mut ManuallyDrop) -> &mut T { // SAFETY: ManuallyDrop is represented the same as T, // so their pointers should be compatible with an `as` cast unsafe { &mut *(md as *mut ManuallyDrop as *mut T) } } /// Const equivalent of [`core::mem::ManuallyDrop::take`] with the same safety requirements. #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[inline(always)] pub const unsafe fn take(md: &mut ManuallyDrop) -> T { // SAFETY: ManuallyDrop is represented the same as T, // so it's valid to read T out of a pointer to ManuallyDrop unsafe { (md as *mut ManuallyDrop as *mut T).read() } } konst-0.3.16/src/maybe_uninit.rs000064400000000000000000000160021046102023000146700ustar 00000000000000//! Const fn equivalents of //! [`MaybeUninit`](https://doc.rust-lang.org/core/mem/union.MaybeUninit.html) methods. //! //! # Removed in 0.3.0 //! //! These functions were removed in 0.3.0 because there is an equivalent //! const fn in the standard library: //! //! - `as_ptr`: [`MaybeUninit::as_ptr`] //! - `assume_init`: [`MaybeUninit::assume_init`] //! - `assume_init_ref`: [`MaybeUninit::assume_init_ref`] //! //! use core::mem::MaybeUninit; declare_generic_const! { /// Generic constant for an uninitialized `MaybeUninit`. /// Usable to safely construct a `[MaybeUninit; LEN]` when `T` is non-`Copy`. /// /// As of Rust 1.65.0, `[MaybeUninit::uninit(); LEN]` is not valid for non-`Copy` types, /// but `[CONST; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::maybe_uninit::{self as mu, UNINIT}; /// /// use std::mem::{self, MaybeUninit}; /// /// // Intentionally doesn't implement `Copy` /// #[derive(Debug, PartialEq, Eq, Clone)] /// struct NonCopy(u8); /// /// const INITS: [NonCopy; 5] = { /// let mut uninits = [UNINIT::::V; 5]; /// konst::for_range!{i in 0..5=> /// uninits[i] = MaybeUninit::new(NonCopy(i as u8 * 3)); /// } /// unsafe{ mu::array_assume_init(uninits) } /// }; /// /// assert_eq!(INITS, [NonCopy(0), NonCopy(3), NonCopy(6), NonCopy(9), NonCopy(12)]); /// for[T] pub const UNINIT[T]: MaybeUninit = MaybeUninit::uninit(); } declare_generic_const! { /// Generic constant for an uninitialized `[MaybeUninit; N]`. /// /// # Example /// /// ```rust /// use konst::maybe_uninit::UNINIT_ARRAY; /// /// use std::mem::{self, MaybeUninit}; /// /// const INITS: [[u8; 2]; 2] = { /// let mut uninits: [[MaybeUninit; 2]; 2] = [UNINIT_ARRAY::::V; 2]; /// /// uninits[0] = [MaybeUninit::new(3), MaybeUninit::new(5)]; /// uninits[1] = [MaybeUninit::new(8), MaybeUninit::new(13)]; /// /// unsafe{ mem::transmute(uninits) } /// }; /// /// assert_eq!(INITS, [[3, 5], [8, 13]]); /// ``` for[T, const N: usize] pub const UNINIT_ARRAY[T; N]: [MaybeUninit; N] = [UNINIT::V; N]; } /// Const equivalent of [`MaybeUninit::uninit_array`](core::mem::MaybeUninit::uninit_array) /// /// # Example /// /// ```rust /// use konst::maybe_uninit as mu; /// /// use std::mem::{self, MaybeUninit}; /// /// const INITS: [u8; 2] = { /// let mut uninits = mu::uninit_array::(); /// /// uninits[0] = MaybeUninit::new(21); /// uninits[1] = MaybeUninit::new(34); /// /// unsafe{ mu::array_assume_init(uninits) } /// }; /// /// assert_eq!(INITS, [21, 34]); /// ``` pub use konst_kernel::maybe_uninit::uninit_array; /// Const equivalent of [`MaybeUninit::assume_init_mut`](core::mem::MaybeUninit::assume_init_mut) /// /// # Safety /// /// This has [the same safety requirements as `MaybeUninit::assume_init_mut` /// ](https://doc.rust-lang.org/1.55.0/core/mem/union.MaybeUninit.html#safety-3) /// /// # Example /// /// ```rust /// use std::cmp::Ordering; /// use std::mem::MaybeUninit; /// /// use konst::maybe_uninit; /// /// const unsafe fn mutate_mu(mu: &mut MaybeUninit) -> u32 { /// let mutref = maybe_uninit::assume_init_mut(mu); /// *mutref += 100; /// *mutref /// } /// /// const MU: (MaybeUninit, [u32; 3]) = { /// let mut mu = MaybeUninit::new(5); /// let array = unsafe{ /// [mutate_mu(&mut mu), mutate_mu(&mut mu), mutate_mu(&mut mu)] /// }; /// (mu, array) /// }; /// /// unsafe{ assert_eq!(MU.0.assume_init(), 305); } /// assert_eq!(MU.1, [105, 205, 305]); /// /// ``` #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[inline(always)] pub const unsafe fn assume_init_mut(md: &mut MaybeUninit) -> &mut T { &mut *(md as *mut MaybeUninit as *mut T) } /// Const equivalent of [`MaybeUninit::write`](core::mem::MaybeUninit::write) /// /// # Example /// /// ```rust /// use std::cmp::Ordering; /// use std::mem::MaybeUninit; /// /// use konst::maybe_uninit; /// /// const fn cond_init(mu: &mut MaybeUninit, value: u32) -> Option<&mut u32> { /// if value % 3 != 0 { /// Some(maybe_uninit::write(mu, value)) /// } else { /// None /// } /// } /// /// let mut mu = MaybeUninit::uninit(); /// assert_eq!(cond_init(&mut mu, 0), None); /// assert_eq!(cond_init(&mut mu, 1), Some(&mut 1)); /// assert_eq!(cond_init(&mut mu, 2), Some(&mut 2)); /// assert_eq!(cond_init(&mut mu, 3), None); /// assert_eq!(cond_init(&mut mu, 4), Some(&mut 4)); /// assert_eq!(cond_init(&mut mu, 5), Some(&mut 5)); /// assert_eq!(cond_init(&mut mu, 6), None); /// /// ``` #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[inline(always)] pub const fn write(md: &mut MaybeUninit, value: T) -> &mut T { *md = MaybeUninit::new(value); unsafe { &mut *(md as *mut MaybeUninit as *mut T) } } /// Const equivalent of [`MaybeUninit::as_mut_ptr`]. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// Initializing a `#[repr(u8)]` enum /// /// ```rust /// use std::mem::MaybeUninit; /// /// use konst::maybe_uninit as mu; /// /// const ENUM: Enum = { /// let mut mu = MaybeUninit::::uninit(); /// /// let ptr = mu::as_mut_ptr(&mut mu).cast::>(); /// unsafe{ /// *ptr = MaybeUninit::new(Discr::Bar); /// mu.assume_init() /// } /// }; /// /// unsafe { /// assert_eq!(ENUM, Enum::Bar); /// } /// /// #[repr(u8)] /// enum Discr { /// Foo, /// Bar, /// Baz, /// } /// /// #[repr(u8)] /// #[derive(Debug, PartialEq)] /// enum Enum { /// Foo(u8), /// Bar, /// Baz{s: String}, /// } /// /// ``` /// /// [`MaybeUninit::as_mut_ptr`]: /// https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#method.as_mut_ptr #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[inline(always)] pub const fn as_mut_ptr(md: &mut MaybeUninit) -> *mut T { md as *mut MaybeUninit as *mut T } /// Const equivalent of /// [`MaybeUninit::array_assume_init`](core::mem::MaybeUninit::array_assume_init) /// /// # Safety /// /// This has [the same safety requirements as `MaybeUninit::array_assume_init` /// ](https://doc.rust-lang.org/1.55.0/core/mem/union.MaybeUninit.html#safety-5) /// /// # Example /// /// ```rust /// use std::mem::MaybeUninit; /// /// use konst::maybe_uninit; /// /// const INIT: [u16; 10] = { /// let mut arr: [MaybeUninit; 10] = maybe_uninit::UNINIT_ARRAY::V; /// /// let mut i = 0usize; /// while i < 10 { /// let x = (i as u16) + 1; /// arr[i as usize] = MaybeUninit::new(x * x); /// i += 1; /// } /// /// unsafe{ maybe_uninit::array_assume_init(arr) } /// }; /// /// assert_eq!(INIT, [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]); /// /// ``` pub use konst_kernel::maybe_uninit::array_assume_init; konst-0.3.16/src/nonzero/cmp.rs000064400000000000000000000051271046102023000144640ustar 00000000000000use core::{ cmp::Ordering, num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, }, }; macro_rules! declare_nonzero_integers { ( ($type:ty, ($eq_fn_name:ident, $cmp_fn_name:ident)) docs( $docs_eq:expr, $docs_cmp:expr, ) ) => { __delegate_const_eq! { #[doc = $docs_eq] pub const fn $eq_fn_name(copy left: $type, right: $type) -> bool { left.get() == right.get() } } __delegate_const_ord! { #[doc = $docs_cmp] pub const fn $cmp_fn_name(copy left: $type, right: $type) -> Ordering { cmp_int!(left.get(), right.get()) } } }; } __declare_fns_with_docs! { (NonZeroU8, (eq_nonzerou8, cmp_nonzerou8)) (NonZeroI8, (eq_nonzeroi8, cmp_nonzeroi8)) (NonZeroU16, (eq_nonzerou16, cmp_nonzerou16)) (NonZeroI16, (eq_nonzeroi16, cmp_nonzeroi16)) (NonZeroU32, (eq_nonzerou32, cmp_nonzerou32)) (NonZeroI32, (eq_nonzeroi32, cmp_nonzeroi32)) (NonZeroU64, (eq_nonzerou64, cmp_nonzerou64)) (NonZeroI64, (eq_nonzeroi64, cmp_nonzeroi64)) (NonZeroU128, (eq_nonzerou128, cmp_nonzerou128)) (NonZeroI128, (eq_nonzeroi128, cmp_nonzeroi128)) (NonZeroUsize, (eq_nonzerousize, cmp_nonzerousize)) (NonZeroIsize, (eq_nonzeroisize, cmp_nonzeroisize)) docs(default) macro = declare_nonzero_integers!(), } __declare_fns_with_docs! { (Option, (eq_option_nonzerou8, cmp_option_nonzerou8)) (Option, (eq_option_nonzeroi8, cmp_option_nonzeroi8)) (Option, (eq_option_nonzerou16, cmp_option_nonzerou16)) (Option, (eq_option_nonzeroi16, cmp_option_nonzeroi16)) (Option, (eq_option_nonzerou32, cmp_option_nonzerou32)) (Option, (eq_option_nonzeroi32, cmp_option_nonzeroi32)) (Option, (eq_option_nonzerou64, cmp_option_nonzerou64)) (Option, (eq_option_nonzeroi64, cmp_option_nonzeroi64)) (Option, (eq_option_nonzerou128, cmp_option_nonzerou128)) (Option, (eq_option_nonzeroi128, cmp_option_nonzeroi128)) (Option, (eq_option_nonzerousize, cmp_option_nonzerousize)) (Option, (eq_option_nonzeroisize, cmp_option_nonzeroisize)) docs(default) macro = __impl_option_cmp_fns!( params(l, r) eq_comparison = l.get() == r.get(), cmp_comparison = cmp_int!(l.get(), r.get()), parameter_copyability = copy, ), } konst-0.3.16/src/nonzero.rs000064400000000000000000000003351046102023000137010ustar 00000000000000//! `const fn` equivalents of `NonZero*` methods. /// `const fn`s for comparing `NonZero*` types for equality and ordering. #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; konst-0.3.16/src/option.rs000064400000000000000000000171761046102023000135320ustar 00000000000000//! `const` equivalents of `Option` methods. /// A const equivalent of [`Option::unwrap`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::option::unwrap; /// /// use std::num::NonZeroUsize; /// /// const TEN: NonZeroUsize = unwrap!(NonZeroUsize::new(10)); /// /// assert_eq!(TEN.get(), 10); /// ``` #[doc(inline)] pub use konst_kernel::opt_unwrap as unwrap; /// A const equivalent of [`Option::unwrap_or`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[u32] = &[ /// option::unwrap_or!(Some(3), 10000), /// option::unwrap_or!(None, 5), /// ]; /// /// assert_eq!(ARR, &[3, 5]); /// /// ``` /// #[doc(inline)] pub use konst_kernel::opt_unwrap_or as unwrap_or; /// A const equivalent of [`Option::unwrap_or_else`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[u32] = &[ /// // You can use a closure-like syntax to run code when the Option argument is None. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::unwrap_or_else!(Some(3), || loop{}), /// option::unwrap_or_else!(None, || 5), /// /// // You can also pass functions /// option::unwrap_or_else!(Some(8), thirteen), /// option::unwrap_or_else!(None, thirteen), /// ]; /// /// assert_eq!(ARR, &[3, 5, 8, 13]); /// /// const fn thirteen() -> u32 { /// 13 /// } /// ``` /// #[doc(inline)] pub use konst_kernel::opt_unwrap_or_else as unwrap_or_else; /// A const equivalent of [`Option::ok_or`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Result] = &[ /// option::ok_or!(Some(3), 10000), /// option::ok_or!(None, 5), /// ]; /// /// assert_eq!(ARR, &[Ok(3), Err(5)]); /// /// ``` #[doc(inline)] pub use konst_kernel::opt_ok_or as ok_or; /// A const equivalent of [`Option::ok_or_else`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Result] = &[ /// // You can use a closure-like syntax to run code when the Option argument is None. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::ok_or_else!(Some(3), || loop{}), /// option::ok_or_else!(None, || 5), /// /// // You can also pass functions /// option::ok_or_else!(Some(8), thirteen), /// option::ok_or_else!(None, thirteen), /// ]; /// /// assert_eq!(ARR, &[Ok(3), Err(5), Ok(8), Err(13)]); /// /// const fn thirteen() -> u32 { /// 13 /// } /// ``` #[doc(inline)] pub use konst_kernel::opt_ok_or_else as ok_or_else; /// A const equivalent of [`Option::map`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Option] = &[ /// // You can use a closure-like syntax to pass code that maps the Some variant. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::map!(Some(3), |x| x * 3), /// option::map!(None::, |_| loop{}), /// /// // You can also pass functions /// option::map!(Some(8), double), /// option::map!(None::, double), /// ]; /// /// assert_eq!(ARR, &[Some(9), None, Some(16), None]); /// /// const fn double(x: u32) -> u32 { /// x * 2 /// } /// /// ``` #[doc(inline)] pub use konst_kernel::opt_map as map; /// A const equivalent of [`Option::and_then`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Option] = &[ /// // You can use a closure-like syntax to pass code that uses the value in the Some variant. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::and_then!(Some(3), |x| Some(x * 3)), /// option::and_then!(Some(3), |_| None), /// option::and_then!(None::, |_| loop{}), /// /// // You can also pass functions /// option::and_then!(Some(23), checked_sub), /// option::and_then!(Some(9), checked_sub), /// option::and_then!(None::, checked_sub), /// ]; /// /// assert_eq!(ARR, &[Some(9), None, None, Some(13), None, None]); /// /// const fn checked_sub(x: u32) -> Option { /// # /* /// x.checked_sub(10) /// # */ /// # let (ret, overflowed) = x.overflowing_sub(10); /// # if overflowed { None } else { Some(ret) } /// } /// /// ``` #[doc(inline)] pub use konst_kernel::opt_and_then as and_then; /// A const equivalent of [`Option::or_else`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Option] = &[ /// // You can use a closure-like syntax to pass code that runs on None. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::or_else!(Some(3), || loop{}), /// option::or_else!(None::, || Some(5)), /// /// // You can also pass functions /// option::or_else!(Some(8), thirteen), /// option::or_else!(None::, thirteen), /// ]; /// /// assert_eq!(ARR, &[Some(3), Some(5), Some(8), Some(13)]); /// /// const fn thirteen() -> Option { /// Some(13) /// } /// /// ``` #[doc(inline)] pub use konst_kernel::opt_or_else as or_else; /// A const equivalent of [`Option::flatten`] /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Option] = &[ /// option::flatten!(Some(Some(8))), /// option::flatten!(None), /// ]; /// /// assert_eq!(ARR, &[Some(8), None]); /// /// ``` #[doc(inline)] pub use konst_kernel::opt_flatten as flatten; /// A const equivalent of [`Option::filter`] /// /// # Example /// /// ``` /// use konst::option; /// /// const ARR: &[Option] = &[ /// // You can use a closure-like syntax to pass code that filters the Some variant. /// // `return` inside the "closure" returns from the function where this macro is called. /// option::filter!(Some(0), |&x| x == 0), /// option::filter!(Some(1), |x| *x == 0), /// option::filter!(None, |_| loop{}), /// /// // You can also pass functions /// option::filter!(Some(3), is_odd), /// option::filter!(Some(4), is_odd), /// option::filter!(None, is_odd), /// ]; /// /// assert_eq!(ARR, &[Some(0), None, None, Some(3), None, None]); /// /// const fn is_odd(x: &u32) -> bool { /// *x % 2 == 1 /// } /// /// ``` #[doc(inline)] pub use konst_kernel::opt_filter as filter; /// A const equivalent of the [`Option::copied`] method. /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::option; /// /// const fn get_last(slice: &[u64]) -> Option { /// option::copied(slice.last()) /// } /// /// assert_eq!(get_last(&[]), None); /// assert_eq!(get_last(&[16]), Some(16)); /// assert_eq!(get_last(&[3, 5, 8, 13]), Some(13)); /// /// /// ``` pub const fn copied(opt: Option<&T>) -> Option { match opt { Some(x) => Some(*x), None => None, } } declare_generic_const! { /// Usable to do `[None::; LEN]` when `T` is non-`Copy`. /// /// As of Rust 1.65.0, `[None::; LEN]` is not valid for non-`Copy` types, /// but `[CONST; LEN]` does work, like in the example below. /// /// # Example /// /// ```rust /// use konst::option::NONE; /// /// use std::mem::{self, MaybeUninit}; /// /// const TEN: [Option; 10] = [NONE::V; 10]; /// /// let ten = [NONE::::V; 10]; /// /// // the `vec` macro only needs `Option` to be clonable, not Copy. /// assert_eq!(vec![None::; 10], TEN); /// /// assert_eq!(vec![None::; 10], ten); /// for[T] pub const NONE[T]: Option = None; } konst-0.3.16/src/other/cmp.rs000064400000000000000000000033251046102023000141110ustar 00000000000000use core::{ cmp::Ordering, marker::{PhantomData, PhantomPinned}, }; __delegate_const_eq! { /// Compares two `Ordering` for equality. #[inline] pub const fn eq_ordering(copy left: Ordering, right: Ordering) -> bool { left as i8 == right as i8 } } __delegate_const_ord! { /// Compares two `Ordering`, returning the ordering of `left` relative to `right`. #[inline] pub const fn cmp_ordering(copy left: Ordering, right: Ordering) -> Ordering { cmp_int!(left as i8, right as i8) } } __declare_fns_with_docs! { (Option, (eq_option_ordering, cmp_option_ordering)) docs(default) macro = __impl_option_cmp_fns!( params(l, r) eq_comparison = eq_ordering(l, r), cmp_comparison = cmp_ordering(l, r), parameter_copyability = copy, ), } macro_rules! impl_for_marker_traits{ ( ($type:ty, ($eq_fn_name:ident, $cmp_fn_name:ident) $(, for[$($generic:tt)*] )? ) docs( $docs_eq:expr, $docs_cmp:expr, ) ) => { __delegate_const_eq! { $(for[$($generic)*] )? #[doc = $docs_eq] #[inline] pub const fn $eq_fn_name(copy _l: $type, _r: $type) -> bool { true } } __delegate_const_ord! { $(for[$($generic)*] )? #[doc = $docs_cmp] #[inline] pub const fn $cmp_fn_name(copy _l: $type, _r: $type) -> Ordering { Ordering::Equal } } } } __declare_fns_with_docs! { (PhantomData, (eq_phantomdata, cmp_phantomdata), for[T,]) (PhantomPinned, (eq_phantompinned, cmp_phantompinned)) docs(default) macro = impl_for_marker_traits!(), } konst-0.3.16/src/other.rs000064400000000000000000000004161046102023000133300ustar 00000000000000//! `const fn` equivalents of methods from miscelaneous standard library types. /// `const fn`s for comparing miscelaneous standard library types for equality and ordering. #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; konst-0.3.16/src/parsing/get_parser.rs000064400000000000000000000061741046102023000160140ustar 00000000000000use crate::parsing::{ParseValueResult, Parser}; use core::marker::PhantomData; /// Gets a type that parses `Self` with a `parse_with` method. /// /// Implementing this trait allows parsing a type with the [`parse_with`] macro. /// /// # Implementing this trait /// /// You can implement this trait like this: /// ```rust /// # struct SomeType; /// # struct SomeParser; /// # use konst::parsing::HasParser; /// impl HasParser for SomeType { /// // This is usually `Self` for user-defined types. /// type Parser = SomeParser; /// } /// ``` /// Then `SomeParser` is expected to have a `parse_with` associated function with this signature: /// ```rust /// # /* /// impl SomeParser { /// const fn parse_with<'a>( /// _: konst::Parser<'a> /// ) -> Result<(This, konst::Parser<'a>), SomeErrorType> /// } /// # */ /// ``` /// /// # Example /// /// ```rust /// use konst::{parse_with, try_rebind, unwrap_ctx}; /// /// use konst::parsing::{HasParser, Parser, ParseValueResult}; /// /// const PAIR: Pair = { /// let parser = Parser::new("100,200"); /// unwrap_ctx!(parse_with!(parser, Pair)).0 /// }; /// /// assert_eq!(PAIR, Pair(100, 200)); /// /// /// #[derive(Debug, PartialEq)] /// struct Pair(u32, u64); /// /// impl HasParser for Pair { /// type Parser = Self; /// } /// /// impl Pair { /// const fn parse_with(mut parser: Parser<'_>) -> ParseValueResult<'_, Self> { /// try_rebind!{(let left, parser) = parse_with!(parser, u32)} /// try_rebind!{parser = parser.strip_prefix(',')} /// try_rebind!{(let right, parser) = parse_with!(parser, u64)} /// /// Ok((Pair(left, right), parser)) /// } /// } /// ``` /// /// [`parse_with`]: ../macro.parse_with.html /// [`HasParser::Parser`]: #associatedtype.Parser /// pub trait HasParser: Sized { /// The type that parses `Self` with its `parse_with` associated function. /// /// This is usually `Self` for user-defined types. type Parser; } //////////////////////////////////////////////////////////////////////////////// /// Parses a standard library type, determined by the `StdType` type parameter. /// /// /// pub struct StdParser(PhantomData); macro_rules! impl_std_parser_one { ($method:ident, $type:ty, $parse_with_docs:expr) => { impl HasParser for $type { type Parser = StdParser<$type>; } impl StdParser<$type> { #[doc = $parse_with_docs] pub const fn parse_with(parser: Parser<'_>) -> ParseValueResult<'_, $type> { parser.$method() } } }; } macro_rules! impl_std_parser { ($($method:ident -> $type:ty;)*) => ( $( impl_std_parser_one!{ $method, $type, concat!("Atempts to parse `", stringify!($type), "`") } )* ) } impl_std_parser! { parse_u128 -> u128; parse_i128 -> i128; parse_u64 -> u64; parse_i64 -> i64; parse_u32 -> u32; parse_i32 -> i32; parse_u16 -> u16; parse_i16 -> i16; parse_u8 -> u8; parse_i8 -> i8; parse_usize -> usize; parse_isize -> isize; parse_bool -> bool; } konst-0.3.16/src/parsing/non_parsing_methods.rs000064400000000000000000000111701046102023000177110ustar 00000000000000use super::{ErrorKind, ParseDirection, ParseError, Parser}; use crate::string; // Putting this impl in a submodule so that it appears before // the integer parsing methods in the docs impl<'a> Parser<'a> { /// Constructs a Parser from a string. /// /// This parser start with a `start_offset` of `0`, /// [`with_start_offset`](Self::with_start_offset) /// is preferable for parsing after the start of a string. #[inline] pub const fn new(string: &'a str) -> Self { Self { parse_direction: ParseDirection::FromStart, start_offset: 0, yielded_last_split: false, str: string, } } /// Constructs a Parser from `string` which is at `start_offset` /// inside some other string. /// /// # Example /// /// ```rust /// use konst::parsing::{ErrorKind, Parser}; /// /// // indices /// // 0 4 8 /// // | | | /// // "foo bar baz" /// let substr = konst::string::str_from("foo bar baz", 4); /// /// let parser = Parser::with_start_offset(substr, 4); /// assert_eq!(parser.remainder(), "bar baz"); /// /// let (bar, parser) = parser.split(' ').unwrap(); /// assert_eq!(bar, "bar"); /// /// let err = parser.split_terminator(' ').unwrap_err(); /// /// assert_eq!(parser.remainder(), "baz"); /// assert_eq!(err.offset(), 8); /// assert_eq!(err.kind(), ErrorKind::DelimiterNotFound); /// /// ``` #[inline] pub const fn with_start_offset(string: &'a str, start_offset: usize) -> Self { Self { parse_direction: ParseDirection::FromStart, start_offset: start_offset as u32, yielded_last_split: false, str: string, } } /// Skips `byte_count` bytes from the parsed string, /// as well as however many bytes are required to be on a char boundary. pub const fn skip(mut self, mut byte_count: usize) -> Self { let bytes = self.str.as_bytes(); if byte_count > bytes.len() { byte_count = bytes.len() } else { use konst_kernel::string::__is_char_boundary_bytes; while !__is_char_boundary_bytes(bytes, byte_count) { byte_count += 1; } }; self.parse_direction = ParseDirection::FromStart; self.start_offset += byte_count as u32; self.str = string::str_from(self.str, byte_count); self } /// Skips `byte_count` bytes from the back of the parsed string, /// as well as however many bytes are required to be on a char boundary. pub const fn skip_back(mut self, byte_count: usize) -> Self { use konst_kernel::string::__is_char_boundary_bytes; let bytes = self.str.as_bytes(); let mut pos = self.str.len().saturating_sub(byte_count); while !__is_char_boundary_bytes(bytes, pos) { pos -= 1; } self.parse_direction = ParseDirection::FromEnd; self.str = string::str_up_to(self.str, pos); self } /// Returns the remaining, unparsed string. #[inline(always)] pub const fn remainder(self) -> &'a str { self.str } /// Gets the byte offset of this parser in the str slice that this /// was constructed from. #[inline(always)] pub const fn start_offset(self) -> usize { self.start_offset as _ } /// Gets the end byte offset of this parser in the str slice that this /// was constructed from. #[inline(always)] pub const fn end_offset(self) -> usize { self.start_offset as usize + self.str.len() } /// The direction that the parser was last mutated from. pub const fn parse_direction(self) -> ParseDirection { self.parse_direction } /// Constructs a [`ParseError`] for this point in parsing. /// /// [`ParseError`]: struct.ParseError.html pub const fn into_error(self, kind: ErrorKind) -> ParseError<'a> { ParseError::new(self, kind) } /// Constructs a [`ParseError`] for this point in parsing, /// for an [`ErrorKind::Other`] with a custom error message. /// /// [`ParseError`]: struct.ParseError.html /// [`ErrorKind::Other`]: ./enum.ErrorKind.html#variant.Other pub const fn into_other_error(self, string: &'static &'static str) -> ParseError<'a> { ParseError::other_error(self, string) } /// The amount of unparsed bytes. #[inline(always)] pub const fn len(self) -> usize { self.str.len() } /// Whether there are any bytes left to parse. #[inline(always)] pub const fn is_empty(self) -> bool { self.str.is_empty() } } konst-0.3.16/src/parsing/parse_errors.rs000064400000000000000000000141641046102023000163650ustar 00000000000000use crate::Parser; use core::{ fmt::{self, Display}, marker::PhantomData, }; /// Error returned by all parsing methods that return Result. /// /// This error type knows [`where`](#method.offset) the error happened, /// in what [`direction`](#method.error_direction) the string was being parsed, /// and the [`kind`](#method.kind) of error that happened. #[derive(Debug, PartialEq, Eq, Clone)] pub struct ParseError<'a> { start_offset: u32, end_offset: u32, direction: ParseDirection, kind: ErrorKind, extra_message: &'static &'static str, // Just in case that it goes back to storing the parser _lifetime: PhantomData<&'a [u8]>, } impl<'a> ParseError<'a> { /// Constructs a `ParseError`. #[inline(always)] pub const fn new(parser: Parser<'a>, kind: ErrorKind) -> Self { Self { start_offset: parser.start_offset, end_offset: parser.start_offset + parser.str.len() as u32, direction: parser.parse_direction, kind, extra_message: &"", _lifetime: PhantomData, } } /// Constructs a `ParseError` for an `ErrorKind::Other` error with /// a customized error message. pub const fn other_error(parser: Parser<'a>, extra_message: &'static &'static str) -> Self { Self { start_offset: parser.start_offset, end_offset: parser.start_offset + parser.str.len() as u32, direction: parser.parse_direction, kind: ErrorKind::Other, extra_message, _lifetime: PhantomData, } } /// A const fn equivalent of a clone method. pub const fn copy(&self) -> Self { Self { start_offset: self.start_offset, end_offset: self.end_offset, direction: self.direction, kind: self.kind, extra_message: self.extra_message, _lifetime: PhantomData, } } /// Gets the byte offset of this error in the parsed string that the /// [`Parser`] was constructed from. #[inline(always)] pub const fn offset(&self) -> usize { (match self.direction { ParseDirection::FromStart | ParseDirection::FromBoth => self.start_offset, ParseDirection::FromEnd => self.end_offset, }) as usize } /// The direction that this error happened from, /// either from the start or the end. pub const fn error_direction(&self) -> ParseDirection { self.direction } /// The kind of parsing error that this is. pub const fn kind(&self) -> ErrorKind { self.kind } const fn extra_message(&self) -> &str { self.extra_message } /// For panicking with an error message, /// this is called by the [`unwrap_ctx`] macro. /// /// [`unwrap_ctx`]: ../result/macro.unwrap_ctx.html #[track_caller] pub const fn panic(&self) -> ! { use const_panic::{FmtArg, PanicVal}; const_panic::concat_panic(&[&[ PanicVal::write_str(self.error_for_direction()), PanicVal::from_usize(self.offset(), FmtArg::DEBUG), PanicVal::write_str(" byte offset"), PanicVal::write_str(self.error_suffix()), PanicVal::write_str(self.extra_message()), ]]) } const fn error_for_direction(&self) -> &'static str { match self.direction { ParseDirection::FromStart => "error from the start at the ", ParseDirection::FromEnd => "error from the end at the ", ParseDirection::FromBoth => "error from the start and end at the ", } } const fn error_suffix(&self) -> &'static str { match self.kind { ErrorKind::ParseInteger => " while parsing an integer", ErrorKind::ParseBool => " while parsing a bool", ErrorKind::Find => " while trying to find and skip a pattern", ErrorKind::Strip => " while trying to strip a pattern", ErrorKind::SplitExhausted => ": called split on empty parser", ErrorKind::DelimiterNotFound => ": delimiter (for splitting) could not be found", ErrorKind::Other => { if self.extra_message.is_empty() { " other error" } else { ": " } } } } } impl<'a> Display for ParseError<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.error_for_direction())?; Display::fmt(&self.offset(), f)?; f.write_str(" byte offset")?; f.write_str(self.error_suffix())?; f.write_str(self.extra_message())?; Ok(()) } } //////////////////////////////////////////////////////////////////////////////// /// The direction that a parser was parsing from when an error happened. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum ParseDirection { /// Parsing was attempted from the start of the string FromStart = 0, /// Parsing was attempted from the end of the string FromEnd = 1, /// Parsing was attempted from both the start and end of the string FromBoth = 2, } //////////////////////////////////////////////////////////////////////////////// /// What kind of parsing error this is. #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum ErrorKind { /// Returned from integer parsing methods ParseInteger, /// Returned from `parse_bool` ParseBool, /// Returned from `*find*` methods Find, /// Returned from `strip_*` methods Strip, /// Returned from `split` when the last delimiter-separated/terminated string /// has already been returned SplitExhausted, /// Returned from `split_terminator` when the delimiter could not be found DelimiterNotFound, /// For user-defined types Other, } //////////////////////////////////////////////////////////////////////////////// /// Result alias for functions that mutate the parser fallibly. pub type ParserResult<'a, E = ParseError<'a>> = Result, E>; /// Result alias for functions that parse values. pub type ParseValueResult<'a, T, E = ParseError<'a>> = Result<(T, Parser<'a>), E>; konst-0.3.16/src/parsing/primitive_parsing.rs000064400000000000000000000345351046102023000174160ustar 00000000000000use crate::string; use super::{ErrorKind, ParseDirection, ParseValueResult, Parser}; impl<'a> Parser<'a> { /// Parses a `u128` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_u128`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `u128`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// ```rust /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// unwrap_ctx, try_, /// }; /// /// { /// let parser = Parser::new("12345"); /// let (num, parser) = unwrap_ctx!(parser.parse_u128()); /// assert_eq!(num, 12345); /// assert!(parser.is_empty()); /// } /// /// /// Parses a `[u128; 2]` from a parser starting with `";", eg: `"100;400"`. /// const fn parse_pair(mut parser: Parser<'_>) -> ParseValueResult<'_, [u128; 2]> { /// let mut ret = [0; 2]; /// /// (ret[0], parser) = try_!(parser.parse_u128()); /// /// // parsing the `;``between the integers. /// // /// // Note that because we don't use `.trim_start()` afterwards, /// // this can't be followed by spaces. /// parser = try_!(parser.strip_prefix(";")); /// /// (ret[1], parser) = try_!(parser.parse_u128()); /// /// Ok((ret, parser)) /// } /// const PAIR: ([u128; 2], Parser<'_>) = { /// let parser = Parser::new("1365;6789"); /// unwrap_ctx!(parse_pair(parser)) /// }; /// /// assert_eq!(PAIR.0[0], 1365); /// assert_eq!(PAIR.0[1], 6789); /// /// assert!(PAIR.1.is_empty()); /// /// ``` /// /// [`primitive::parse_u128`]: ../primitive/fn.parse_u128.html pub const fn parse_u128(mut self) -> ParseValueResult<'a, u128> { parse_integer! {unsigned, (u128, u128), self} } /// Parses a `i128` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_i128`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `i128`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// ```rust /// use konst::{Parser, unwrap_ctx, rebind_if_ok}; /// /// { /// let parser = Parser::new("12345"); /// let (num, parser) = unwrap_ctx!(parser.parse_i128()); /// assert_eq!(num, 12345); /// assert!(parser.is_empty()); /// } /// { /// let mut num = 0; /// let mut parser = Parser::new("-54321;6789"); /// /// // `rebind_if_ok` stores the return value of `.parse_i128()` in `num` and `parser`, /// // if `.parse_i128()` returned an `Ok((u128, Parser))`. /// rebind_if_ok!{(num, parser) = parser.parse_i128()} /// assert_eq!(num, -54321); /// assert_eq!(parser.remainder(), ";6789"); /// /// rebind_if_ok!{parser = parser.strip_prefix(";")} /// assert_eq!(parser.remainder(), "6789"); /// /// rebind_if_ok!{(num, parser) = parser.parse_i128()} /// assert_eq!(num, 6789); /// assert!(parser.is_empty()); /// } /// /// ``` /// /// [`primitive::parse_i128`]: ../primitive/fn.parse_i128.html pub const fn parse_i128(mut self) -> ParseValueResult<'a, i128> { parse_integer! {signed, (i128, u128), self} } /// Parses a `u64` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_u64`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `u64`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method. /// /// [`primitive::parse_u64`]: ../primitive/fn.parse_u64.html pub const fn parse_u64(mut self) -> ParseValueResult<'a, u64> { parse_integer! {unsigned, (u64, u64), self} } /// Parses a `i64` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_i64`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `i64`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method. /// /// [`primitive::parse_i64`]: ../primitive/fn.parse_i64.html pub const fn parse_i64(mut self) -> ParseValueResult<'a, i64> { parse_integer! {signed, (i64, u64), self} } /// Parses a `u32` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_u32`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `u32`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method. /// /// [`primitive::parse_u32`]: ../primitive/fn.parse_u32.html pub const fn parse_u32(mut self) -> ParseValueResult<'a, u32> { parse_integer! {unsigned, (u32, u32), self} } /// Parses a `i32` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_i32`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `i32`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method. /// /// [`primitive::parse_i32`]: ../primitive/fn.parse_i32.html pub const fn parse_i32(mut self) -> ParseValueResult<'a, i32> { parse_integer! {signed, (i32, u32), self} } /// Parses a `u16` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_u16`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `u16`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method. /// /// [`primitive::parse_u16`]: ../primitive/fn.parse_u16.html pub const fn parse_u16(mut self) -> ParseValueResult<'a, u16> { parse_integer! {unsigned, (u16, u16), self} } /// Parses a `i16` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_i16`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `i16`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method. /// /// [`primitive::parse_i16`]: ../primitive/fn.parse_i16.html pub const fn parse_i16(mut self) -> ParseValueResult<'a, i16> { parse_integer! {signed, (i16, u16), self} } /// Parses a `u8` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_u8`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `u8`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method. /// /// [`primitive::parse_u8`]: ../primitive/fn.parse_u8.html pub const fn parse_u8(mut self) -> ParseValueResult<'a, u8> { parse_integer! {unsigned, (u8, u8), self} } /// Parses a `i8` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_i8`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `i8`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method. /// /// [`primitive::parse_i8`]: ../primitive/fn.parse_i8.html pub const fn parse_i8(mut self) -> ParseValueResult<'a, i8> { parse_integer! {signed, (i8, u8), self} } /// Parses a `usize` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_usize`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `usize`, and other [`HasParser`](./trait.HasParser.html) types. /// /// [`primitive::parse_usize`]: ../primitive/fn.parse_usize.html pub const fn parse_usize(mut self) -> ParseValueResult<'a, usize> { parse_integer! {unsigned, (usize, usize), self} } /// Parses a `isize` until a non-digit is reached. /// /// To parse an integer from an entire string (erroring on non-digit bytes), /// you can use [`primitive::parse_isize`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `isize`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// For an example for how to use this method, /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method. /// /// [`primitive::parse_isize`]: ../primitive/fn.parse_isize.html pub const fn parse_isize(mut self) -> ParseValueResult<'a, isize> { parse_integer! {signed, (isize, usize), self} } } macro_rules! parse_integer { ($signedness:ident, ($type:ty, $uns:ty), $parser:ident) => (try_parsing! { $parser, FromStart, ret;{ let mut num: $uns; let mut bytes = $parser.str.as_bytes(); parse_integer! {@parse_signed $signedness, ($type, $uns), bytes, num, sign} while let [byte @ b'0'..=b'9', rem @ ..] = bytes { bytes = rem; let (next_mul, overflowed_mul) = num.overflowing_mul(10); let (next_add, overflowed_add) = next_mul.overflowing_add((*byte - b'0') as $uns); if overflowed_mul | overflowed_add { throw!(ErrorKind::ParseInteger) } num = next_add; } parse_integer! {@apply_sign $signedness, ($type, $uns), num, sign} $parser.str = string::str_from($parser.str, $parser.str.len() - bytes.len()); num } }); (@parse_signed signed, ($type:ty, $uns:ty), $bytes:ident, $num:ident, $isneg:ident) => { let $isneg = if let [b'-', rem @ ..] = $bytes { $bytes = rem; true } else { false }; parse_integer!(@parse_signed unsigned, ($type, $uns), $bytes, $num, $isneg) }; (@parse_signed unsigned, ($type:ty, $uns:ty), $bytes:ident, $num:ident, $isneg:ident) => { $num = if let [byte @ b'0'..=b'9', rem @ ..] = $bytes { $bytes = rem; (*byte - b'0') as $uns } else { throw!(ErrorKind::ParseInteger) }; }; (@apply_sign signed, ($type:ty, $uns:ty), $num:ident, $isneg:ident) => { const MAX_POS: $uns = <$type>::MAX as $uns; const MAX_NEG: $uns = <$type>::MIN as $uns; let $num = if $isneg { if $num <= MAX_NEG { ($num as $type).wrapping_neg() } else { throw!(ErrorKind::ParseInteger) } } else { if $num <= MAX_POS { $num as $type } else { throw!(ErrorKind::ParseInteger) } }; }; (@apply_sign unsigned, ($type:ty, $uns:ty), $num:ident, $isneg:ident) => {}; } use parse_integer; //////////////////////////////////////////////////////////////////////////////// impl<'a> Parser<'a> { /// Parses a `bool`. /// /// To parse a bool from an entire string /// (erroring if the string isn't exactly `"true"` or `"false"`), /// you can use [`primitive::parse_bool`] /// /// You also can use the [`parse_with`](../macro.parse_with.html) /// macro to parse a `bool`, and other [`HasParser`](./trait.HasParser.html) types. /// /// # Example /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// { /// let parser = Parser::new("falsemorestring"); /// let (boolean, parser) = unwrap_ctx!(parser.parse_bool()); /// assert_eq!(boolean, false); /// assert_eq!(parser.remainder(), "morestring"); /// } /// { /// let parser = Parser::new("truefoo"); /// let (boolean, parser) = unwrap_ctx!(parser.parse_bool()); /// assert_eq!(boolean, true); /// assert_eq!(parser.remainder(), "foo"); /// } /// /// ``` /// /// [`primitive::parse_bool`]: ../primitive/fn.parse_bool.html pub const fn parse_bool(mut self) -> ParseValueResult<'a, bool> { try_parsing! {self, FromStart, ret; match self.str.as_bytes() { [b't', b'r', b'u', b'e', ..] => { self.str = string::str_from(self.str, 4); true } [b'f', b'a', b'l', b's', b'e', ..] => { self.str = string::str_from(self.str, 5); false } _ => throw!(ErrorKind::ParseBool), } } } } konst-0.3.16/src/parsing.rs000064400000000000000000000700321046102023000136530ustar 00000000000000//! Parsing using `const fn` methods. //! //! You can use the [`Parser`] type to parse from string, //! more information in its documentation. //! //! If you're looking for functions to parse some type from an entire string //! (instead of only part of it), //! then you want to look in the module for that type, eg: [`primitive::parse_bool`]. //! //! If you do want to parse a type fron only part of a string, then you can use //! [`Parser`]'s `parse_*` methods, or the [`parse_with`] macro. //! //! [`Parser`]: ./struct.Parser.html //! [`primitive::parse_bool`]: ../primitive/fn.parse_bool.html //! [`parse_with`]: ../macro.parse_with.html //! mod get_parser; mod non_parsing_methods; mod parse_errors; mod primitive_parsing; ///////////////////////////////////////////////////////////////////////////////// pub use self::{ get_parser::{HasParser, StdParser}, parse_errors::{ErrorKind, ParseDirection, ParseError, ParseValueResult, ParserResult}, }; use crate::string::{self, Pattern}; /// For parsing and traversing over strings in const contexts. /// /// If you're looking for functions to parse some type from an entire string /// (instead of only part of it), /// then you want to look in the module for that type, eg: [`primitive::parse_u64`]. /// /// [`primitive::parse_u64`]: ../primitive/fn.parse_u64.html /// /// # Mutation /// /// Because `konst` only requires Rust 1.65.0, /// in order to mutate a parser you must reassign the parser returned by its methods. ///
eg: `parser = parser.trim_start();` /// /// To help make this more ergonomic for `Result`-returning methods, you can use these macros: /// /// - [`try_rebind`]: /// Like the `?` operator, /// but also reassigns variables and declares new ones with the value in the `Ok` variant. /// /// - [`rebind_if_ok`]: /// Like an `if let Ok`, /// but also reassigns variables and declares new ones with the value in the `Ok` variant. /// /// - [`parser_method`]: /// Parses any of the string literal patterns using a supported `Parser` method. /// /// [`try_rebind`]: ../macro.try_rebind.html /// [`rebind_if_ok`]: ../macro.rebind_if_ok.html /// [`parser_method`]: crate::parser_method /// /// # Examples /// /// ### Parsing a variable-length array /// /// Parses a variable-length array, requires the length to appear before the array. /// /// This example requires the "parsing_proc" feature (enabled by default) /// because it uses the [`parser_method`] macro. /// #[cfg_attr(feature = "parsing_proc", doc = "```rust")] #[cfg_attr(not(feature = "parsing_proc"), doc = "```ignore")] /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// for_range, parser_method, try_, unwrap_ctx, /// }; /// /// // We need to parse the length into a separate const to use it as the length of the array. /// const LEN_AND_PARSER: (usize, Parser<'_>) = { /// let input = "\ /// 6; /// up, 0, 90, down, left, right, /// "; /// /// let parser = Parser::new(input); /// let (len, parser) = unwrap_ctx!(parser.parse_usize()); /// (len, unwrap_ctx!(parser.strip_prefix(';'))) /// }; /// /// const ANGLES: [Angle; LEN_AND_PARSER.0] = /// unwrap_ctx!(Angle::parse_array(LEN_AND_PARSER.1)).0; /// /// fn main() { /// assert_eq!( /// ANGLES, /// [Angle::UP, Angle::UP, Angle::RIGHT, Angle::DOWN, Angle::LEFT, Angle::RIGHT] /// ); /// } /// /// /// /// #[derive(Debug, PartialEq, Eq, Copy, Clone)] /// struct Angle(u16); /// /// impl Angle { /// pub const UP: Self = Self(0); /// pub const RIGHT: Self = Self(90); /// pub const DOWN: Self = Self(180); /// pub const LEFT: Self = Self(270); /// /// pub const fn new(n: u64) -> Angle { /// Angle((n % 360) as u16) /// } /// /// const fn parse_array( /// mut parser: Parser<'_> /// ) -> ParseValueResult<'_, [Angle; LEN]> { /// let mut ret = [Angle::UP; LEN]; /// /// for_range!{i in 0..LEN => /// (ret[i], parser) = try_!(Angle::parse(parser.trim_start())); /// /// parser = parser.trim_start(); /// if !parser.is_empty() { /// parser = try_!(parser.strip_prefix(',')); /// } /// } /// Ok((ret, parser)) /// } /// /// pub const fn parse(mut parser: Parser<'_>) -> ParseValueResult<'_, Angle> { /// // this doesn't use the `rebind_if_ok` macro because it returns early. /// if let Ok((angle, parser)) = parser.parse_u64() { /// return Ok((Self::new(angle), parser)) /// } /// /// let angle = parser_method!{parser, strip_prefix; /// "up" => Self::UP, /// "right" => Self::RIGHT, /// "down" => Self::DOWN, /// "left" => Self::LEFT, /// _ => return Err(parser.into_other_error(&"could not parse Direction")) /// }; /// Ok((angle, parser)) /// } /// } /// /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct Parser<'a> { parse_direction: ParseDirection, // this allows split methods to return the empty string after // the last delimiter, but only once. yielded_last_split: bool, /// The offset of `str` in the string that this was created from. start_offset: u32, str: &'a str, } impl<'a> Parser<'a> { /// Gets the string up to (but not including) `delimiter`. /// /// This is like [`Parser::split`], /// except that it always requires that the delimiter can be found. /// /// # Return value /// /// If either the string is empty or the delimiter can't be found, /// this return an error. /// /// If the delimiter can be found and the string is non-empty. /// this returns the string before the delimiter, /// moving the parser to after the delimiter. /// /// # Example /// /// ```rust /// use konst::{ /// result::unwrap_ctx, /// Parser, /// }; /// /// assert_eq!(VARS, ["foo", "bar", "baz"]); /// /// const VARS: [&str; 3] = { /// let parser = Parser::new("foo,bar,baz"); /// /// let (foo, parser) = unwrap_ctx!(parser.split_terminator(',')); /// let (bar, parser) = unwrap_ctx!(parser.split_terminator(',')); /// /// // `.split_terminator(',')` errors here /// // because there's no `,` in the remainder of the string, /// assert!(parser.split_terminator(',').is_err()); /// /// [foo, bar, parser.remainder()] /// }; /// /// ``` pub const fn split_terminator<'p, P>( mut self, delimiter: P, ) -> Result<(&'a str, Self), ParseError<'a>> where P: Pattern<'p>, { try_parsing! {self, FromStart, ret; if self.str.is_empty() || self.yielded_last_split { throw!(if self.yielded_last_split { ErrorKind::SplitExhausted } else { ErrorKind::DelimiterNotFound }) } match string::split_once(self.str, delimiter) { Some((before, after)) => { self.yielded_last_split = after.is_empty(); self.str = after; before } None => throw!(ErrorKind::DelimiterNotFound), } } } /// Gets the string after `delimiter`. /// /// This is like [`Parser::rsplit`], /// except that it always requires that the delimiter can be found. /// /// # Return value /// /// If either the string is empty or the delimiter can't be found, /// this return an error. /// /// If the delimiter can be found and the string is non-empty. /// this returns the string after the delimiter, /// moving the parser to before the delimiter. /// /// # Example /// /// ```rust /// use konst::{ /// result::unwrap_ctx, /// Parser, /// }; /// /// assert_eq!(VARS, ["baz", "bar", "foo"]); /// /// const VARS: [&str; 3] = { /// let parser = Parser::new("foo,bar,baz"); /// /// let (baz, parser) = unwrap_ctx!(parser.rsplit_terminator(',')); /// let (bar, parser) = unwrap_ctx!(parser.rsplit_terminator(',')); /// /// // `.rsplit_terminator(',')` errors here /// // because there's no `,` in the remainder of the string, /// assert!(parser.rsplit_terminator(',').is_err()); /// /// [baz, bar, parser.remainder()] /// }; /// /// ``` pub const fn rsplit_terminator<'p, P>( mut self, delimiter: P, ) -> Result<(&'a str, Self), ParseError<'a>> where P: Pattern<'p>, { try_parsing! {self, FromEnd, ret; if self.str.is_empty() || self.yielded_last_split { throw!(if self.yielded_last_split { ErrorKind::SplitExhausted } else { ErrorKind::DelimiterNotFound }) } match string::rsplit_once(self.str, delimiter) { Some((after, before)) => { self.yielded_last_split = after.is_empty(); self.str = after; before } None => throw!(ErrorKind::DelimiterNotFound), } } } /// Gets the string up to (but not including) `delimiter`. /// /// # Return value /// /// If the last delimiter-separated string has already been returned, /// this return an error. /// /// If the delimiter can't be found. /// this returns the remainder of the string. /// /// If the delimiter can be found. /// this returns the string before the delimiter, /// moving the parser to after the delimiter. /// /// # Example /// /// ```rust /// use konst::{ /// result::unwrap_ctx, /// Parser, /// }; /// /// assert_eq!(VARS, ["foo", "bar", ""]); /// /// const VARS: [&str; 3] = { /// let parser = Parser::new("foo,bar,"); /// /// let (foo, parser) = unwrap_ctx!(parser.split(',')); /// let (bar, parser) = unwrap_ctx!(parser.split(',')); /// let (empty, parser) = unwrap_ctx!(parser.split(',')); /// /// assert!(parser.split(',').is_err()); /// assert!(parser.remainder().is_empty()); /// /// [foo, bar, empty] /// }; /// /// ``` pub const fn split<'p, P>(mut self, delimiter: P) -> Result<(&'a str, Self), ParseError<'a>> where P: Pattern<'p>, { try_parsing! {self, FromStart, ret; if self.yielded_last_split { throw!(ErrorKind::SplitExhausted) } let (before, after) = match string::split_once(self.str, delimiter) { Some(pair) => pair, None => { self.yielded_last_split = true; (self.str, string::str_from(self.str, self.str.len())) } }; self.str = after; before } } /// Gets the string after `delimiter`. /// /// # Return value /// /// If the last delimiter-separated string has already been returned, /// this return an error. /// /// If the delimiter can't be found. /// this returns the remainder of the string. /// /// If the delimiter can be found. /// this returns the string after the delimiter, /// moving the parser to before the delimiter. /// /// # Example /// /// ```rust /// use konst::{ /// result::unwrap_ctx, /// Parser, /// }; /// /// assert_eq!(VARS, ["baz", "bar", ""]); /// /// const VARS: [&str; 3] = { /// let parser = Parser::new(",bar,baz"); /// /// let (baz, parser) = unwrap_ctx!(parser.rsplit(',')); /// let (bar, parser) = unwrap_ctx!(parser.rsplit(',')); /// let (empty, parser) = unwrap_ctx!(parser.rsplit(',')); /// /// assert!(parser.rsplit(',').is_err()); /// assert!(parser.remainder().is_empty()); /// /// [baz, bar, empty] /// }; /// /// ``` pub const fn rsplit<'p, P>(mut self, delimiter: P) -> Result<(&'a str, Self), ParseError<'a>> where P: Pattern<'p>, { try_parsing! {self, FromEnd, ret; if self.yielded_last_split { throw!(ErrorKind::SplitExhausted) } let (after, before) = match string::rsplit_once(self.str, delimiter) { Some(pair) => pair, None => { self.yielded_last_split = true; (string::str_up_to(self.str, 0), self.str) } }; self.str = after; before } } /// Gets the string up to (but not including) `delimiter`. /// /// # Return value /// /// This behaves the same as [`Parser::split`], /// except that it keeps the delimiter in the parser, /// rather than skip it. /// /// # Example /// /// This example requires the `"parsing_proc"` feature. /// #[cfg_attr(feature = "parsing_proc", doc = "```rust")] #[cfg_attr(not(feature = "parsing_proc"), doc = "```ignore")] /// /// use konst::{ /// parsing::{Parser, ParseValueResult}, /// eq_str, /// for_range, parser_method, try_rebind, unwrap_ctx, /// }; /// /// assert_eq!(VALS, [ /// Value::Str("hello"), /// Value::U64(3), /// Value::U64(5), /// Value::Str("world"), /// ]); /// /// const VALS: [Value<'_>; 4] = { /// let mut arr = [Value::Str(""); 4]; /// let mut parser = Parser::new("shello,i3,i5,sworld"); /// /// for_range!{i in 0..arr.len() => /// (arr[i], parser) = unwrap_ctx!(parse_value(parser)); /// if !parser.is_empty() { /// parser = unwrap_ctx!(parser.strip_prefix(',')) /// } /// } /// /// arr /// }; /// /// /// #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// enum Value<'a> { /// Str(&'a str), /// U64(u64), /// } /// /// pub const fn parse_value(mut parser: Parser<'_>) -> ParseValueResult<'_, Value<'_>> { /// let val = parser_method!{parser, strip_prefix; /// "s" => { /// try_rebind!{(let string, parser) = parser.split_keep(',')} /// Value::Str(string) /// } /// "i" => { /// try_rebind!{(let integer, parser) = parser.parse_u64()} /// Value::U64(integer) /// } /// _ => return Err(parser.into_other_error(&"expected either `s` or `ì`")) /// }; /// Ok((val, parser)) /// } /// ``` /// pub const fn split_keep<'p, P>( mut self, delimiter: P, ) -> Result<(&'a str, Self), ParseError<'a>> where P: Pattern<'p>, { try_parsing! {self, FromStart, ret; if self.yielded_last_split { throw!(ErrorKind::SplitExhausted) } let (before, after) = match string::find(self.str, delimiter) { Some(pos) => string::split_at(self.str, pos), None => { self.yielded_last_split = true; (self.str, string::str_from(self.str, self.str.len())) } }; self.str = after; before } } /// Checks that the parsed string starts with `matched`, /// returning the remainder of the str. /// /// For calling `strip_prefix` with multiple alternative `matched` string literals, /// you can use the [`parser_method`] macro, /// [example](crate::parser_method#parsing-enum-example) /// /// # Examples /// /// ### Basic /// /// ``` /// use konst::{Parser, rebind_if_ok}; /// /// let mut parser = Parser::new("foo;bar;baz;"); /// /// assert!(parser.strip_prefix("aaa").is_err()); /// /// rebind_if_ok!{parser = parser.strip_prefix("foo;")} /// assert_eq!(parser.remainder(), "bar;baz;"); /// /// rebind_if_ok!{parser = parser.strip_prefix("bar;")} /// assert_eq!(parser.remainder(), "baz;"); /// /// rebind_if_ok!{parser = parser.strip_prefix("baz;")} /// assert_eq!(parser.remainder(), ""); /// /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::{Parser, rebind_if_ok}; /// /// let mut parser = Parser::new("abcde"); /// /// rebind_if_ok!{parser = parser.strip_prefix('a')} /// assert_eq!(parser.remainder(), "bcde"); /// /// rebind_if_ok!{parser = parser.strip_prefix('b')} /// assert_eq!(parser.remainder(), "cde"); /// /// rebind_if_ok!{parser = parser.strip_prefix('c')} /// assert_eq!(parser.remainder(), "de"); /// /// ``` /// #[inline] pub const fn strip_prefix<'p, P>(mut self, matched: P) -> Result> where P: Pattern<'p>, { try_parsing! {self, FromStart; match string::strip_prefix(self.str, matched) { Some(x) => self.str = x, None => throw!(ErrorKind::Strip), } } } /// Checks that the parsed string ends with `matched`, /// returning the remainder of the string. /// /// For calling `strip_suffix` with multiple alternative `matched` string literals, /// you can use the [`parser_method`] macro. /// /// # Examples /// /// ### `&str` argument /// /// ``` /// use konst::{Parser, rebind_if_ok}; /// /// let mut parser = Parser::new("foo;bar;baz;"); /// /// assert!(parser.strip_suffix("aaa").is_err()); /// /// rebind_if_ok!{parser = parser.strip_suffix("baz;")} /// assert_eq!(parser.remainder(), "foo;bar;"); /// /// rebind_if_ok!{parser = parser.strip_suffix("bar;")} /// assert_eq!(parser.remainder(), "foo;"); /// /// rebind_if_ok!{parser = parser.strip_suffix("foo;")} /// assert_eq!(parser.remainder(), ""); /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::{Parser, rebind_if_ok}; /// /// let mut parser = Parser::new("edcba"); /// /// rebind_if_ok!{parser = parser.strip_suffix('a')} /// assert_eq!(parser.remainder(), "edcb"); /// /// rebind_if_ok!{parser = parser.strip_suffix('b')} /// assert_eq!(parser.remainder(), "edc"); /// /// rebind_if_ok!{parser = parser.strip_suffix('c')} /// assert_eq!(parser.remainder(), "ed"); /// /// ``` /// #[inline] pub const fn strip_suffix<'p, P>(mut self, matched: P) -> Result> where P: Pattern<'p>, { try_parsing! {self, FromEnd; match string::strip_suffix(self.str, matched) { Some(x) => self.str = x, None => throw!(ErrorKind::Strip), } } } /// Removes whitespace from the start and end of the parsed string. /// /// # Example /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new(" foo\n\t bar "); /// /// parser = parser.trim(); /// assert_eq!(parser.remainder(), "foo\n\t bar"); /// /// ``` pub const fn trim(mut self) -> Self { parsing! {self, FromBoth; self.str = crate::string::trim(self.str); } } /// Removes whitespace from the start of the parsed string. /// /// # Example /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new(" foo\n\t bar"); /// /// parser = parser.trim_start(); /// assert_eq!(parser.remainder(), "foo\n\t bar"); /// /// parser = unwrap_ctx!(parser.strip_prefix("foo")).trim_start(); /// assert_eq!(parser.remainder(), "bar"); /// /// ``` pub const fn trim_start(mut self) -> Self { parsing! {self, FromStart; self.str = crate::string::trim_start(self.str); } } /// Removes whitespace from the end of the parsed string. /// /// # Example /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("foo,\n bar,\n "); /// /// parser = parser.trim_end(); /// assert_eq!(parser.remainder(), "foo,\n bar,"); /// /// parser = unwrap_ctx!(parser.strip_suffix("bar,")).trim_end(); /// assert_eq!(parser.remainder(), "foo,"); /// /// ``` pub const fn trim_end(mut self) -> Self { parsing! {self, FromEnd; self.str = crate::string::trim_end(self.str); } } /// Repeatedly removes all instances of `needle` from /// both the start and end of the parsed string. /// /// # Example /// /// ### `&str` /// /// ```rust /// use konst::Parser; /// /// let mut parser = Parser::new("<><>hello<><>"); /// /// parser = parser.trim_matches("<>"); /// assert_eq!(parser.remainder(), "hello"); /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::Parser; /// /// let mut parser = Parser::new(" world "); /// /// parser = parser.trim_matches(' '); /// assert_eq!(parser.remainder(), "world"); /// ``` /// pub const fn trim_matches<'p, P>(mut self, needle: P) -> Self where P: Pattern<'p>, { parsing! {self, FromBoth; self.str = crate::string::trim_matches(self.str, needle); } } /// Repeatedly removes all instances of `needle` from the start of the parsed string. /// /// For trimming with multiple `needle`s, you can use the [`parser_method`] macro, /// [example](crate::parser_method#trimming-example) /// /// # Example /// /// ### `&str` /// /// ```rust /// use konst::Parser; /// /// { /// let mut parser = Parser::new("HelloHelloHello world!"); /// parser = parser.trim_start_matches("Hello"); /// assert_eq!(parser.remainder(), " world!"); /// } /// { /// let mut parser = Parser::new(" Hi!"); /// parser = parser.trim_start_matches(" "); /// assert_eq!(parser.remainder(), "Hi!"); /// } /// { /// let mut parser = Parser::new("------Bye!"); /// parser = parser.trim_start_matches("----"); /// assert_eq!(parser.remainder(), "--Bye!"); /// } /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::Parser; /// /// let mut parser = Parser::new(" ----world"); /// /// parser = parser.trim_start_matches(' '); /// assert_eq!(parser.remainder(), "----world"); /// /// parser = parser.trim_start_matches('-'); /// assert_eq!(parser.remainder(), "world"); /// /// parser = parser.trim_start_matches('-'); /// assert_eq!(parser.remainder(), "world"); /// /// ``` /// pub const fn trim_start_matches<'p, P>(mut self, needle: P) -> Self where P: Pattern<'p>, { parsing! {self, FromStart; self.str = crate::string::trim_start_matches(self.str, needle); } } /// Repeatedly removes all instances of `needle` from the start of the parsed string. /// /// For trimming with multiple `needle`s, you can use the [`parser_method`] macro, /// [example](crate::parser_method#trimming-example) /// /// # Example /// /// ### `&str` /// /// ```rust /// use konst::Parser; /// /// { /// let mut parser = Parser::new("Hello world!world!world!"); /// parser = parser.trim_end_matches("world!"); /// assert_eq!(parser.remainder(), "Hello "); /// } /// { /// let mut parser = Parser::new("Hi! "); /// parser = parser.trim_end_matches(" "); /// assert_eq!(parser.remainder(), "Hi!"); /// } /// { /// let mut parser = Parser::new("Bye!------"); /// parser = parser.trim_end_matches("----"); /// assert_eq!(parser.remainder(), "Bye!--"); /// } /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::Parser; /// /// let mut parser = Parser::new("world---- "); /// /// parser = parser.trim_end_matches(' '); /// assert_eq!(parser.remainder(), "world----"); /// /// parser = parser.trim_end_matches('-'); /// assert_eq!(parser.remainder(), "world"); /// /// parser = parser.trim_end_matches('-'); /// assert_eq!(parser.remainder(), "world"); /// /// ``` /// pub const fn trim_end_matches<'p, P>(mut self, needle: P) -> Self where P: Pattern<'p>, { parsing! {self, FromEnd; self.str = crate::string::trim_end_matches(self.str, needle); } } /// Skips the parser after the first instance of `needle`. /// /// For calling `find_skip` with multiple alternative `needle` string literals, /// you can use the [`parser_method`] macro, /// [example](crate::parser_method#find-example) /// /// # Example /// /// ### `&str` argument /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("foo--bar,baz--qux"); /// /// parser = unwrap_ctx!(parser.find_skip("--")); /// assert_eq!(parser.remainder(), "bar,baz--qux"); /// /// parser = unwrap_ctx!(parser.find_skip("bar,")); /// assert_eq!(parser.remainder(), "baz--qux"); /// /// parser = unwrap_ctx!(parser.find_skip("--")); /// assert_eq!(parser.remainder(), "qux"); /// /// assert!(parser.find_skip("--").is_err()); /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("foo-bar,baz"); /// /// parser = unwrap_ctx!(parser.find_skip('-')); /// assert_eq!(parser.remainder(), "bar,baz"); /// /// parser = unwrap_ctx!(parser.find_skip(',')); /// assert_eq!(parser.remainder(), "baz"); /// /// ``` /// pub const fn find_skip<'p, P>(mut self, needle: P) -> Result> where P: Pattern<'p>, { try_parsing! {self, FromStart; self.str = match crate::string::find_skip(self.str, needle) { Some(x) => x, None => throw!(ErrorKind::Find), }; } } /// Truncates the parsed string to before the last instance of `needle`. /// /// For calling `rfind_skip` with multiple alternative `needle` string literals, /// you can use the [`parser_method`] macro, /// [example](crate::parser_method#find-example) /// /// # Example /// /// ### `&str` argument /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("foo--bar,baz--qux"); /// /// parser = unwrap_ctx!(parser.rfind_skip("--")); /// assert_eq!(parser.remainder(), "foo--bar,baz"); /// /// parser = unwrap_ctx!(parser.rfind_skip(",baz")); /// assert_eq!(parser.remainder(), "foo--bar"); /// /// parser = unwrap_ctx!(parser.rfind_skip("--")); /// assert_eq!(parser.remainder(), "foo"); /// /// assert!(parser.rfind_skip("--").is_err()); /// /// ``` /// /// ### `char` argument /// /// ```rust /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("foo,bar-baz"); /// /// parser = unwrap_ctx!(parser.rfind_skip('-')); /// assert_eq!(parser.remainder(), "foo,bar"); /// /// parser = unwrap_ctx!(parser.rfind_skip(',')); /// assert_eq!(parser.remainder(), "foo"); /// /// ``` /// pub const fn rfind_skip<'p, P>(mut self, needle: P) -> Result> where P: Pattern<'p>, { try_parsing! {self, FromEnd; self.str = match crate::string::rfind_skip(self.str, needle) { Some(x) => x, None => throw!(ErrorKind::Find), }; } } } konst-0.3.16/src/polymorphism/type_eq_projection_fn.rs000064400000000000000000000133471046102023000213450ustar 00000000000000/// Declares a function for converting a `TypeEq` /// to `TypeEq, Foo>`. /// /// As an alternative to this macro, you can look at [`TypeEq::project`] and [`TypeEq::map`] /// /// [**examples below**](#examples) /// /// [**syntax example**](#syntax) /// /// # Limitations /// /// This macro has the following limitations: /// - It only accepts module paths for a type, /// followed by the generic parameters of that type, /// no concrete generic arguments are allowed. /// /// - It can only map one type parameter, the `T` parameter. /// /// - It cannot parse trait bounds in the type parameter list written /// the normal way, they must be wrapped in parentheses. /// /// - The `T` type parameter can only be bounded in the parameter list /// /// - The `T` type parameter cannot appear in any trait bounds. /// /// The first two limitations can be worked around by passing a type alias /// to the macro. /// /// # Examples /// /// ### Basic /// /// This example shows what the macro does, /// the [motivating example](#motivating-example) shows why one would use it. /// /// ```rust /// use konst::polymorphism::{TypeEq, type_eq_projection_fn}; /// /// #[derive(Debug, PartialEq)] /// struct Foo([T; N]); /// /// // This macro invocation generates: /// // const fn project_to_foo( /// // _: TypeEq, /// // ) -> TypeEq, Foo> /// type_eq_projection_fn!{ /// // `T` must be both the function parameter, and in the return type. /// const fn project_to_foo(T) -> Foo /// } /// /// // a toy example to demonstrate what projecting a TypeEq does /// const fn get_foo<'a, R>(te: TypeEq<&'a str, R>) -> Foo { /// // The type annotation is for the reader /// let te: TypeEq, Foo> = /// project_to_foo::<&'a str, R, 2>(te); /// /// te.to_right(Foo(["foo", "bar"])) /// } /// /// assert_eq!(get_foo(TypeEq::NEW), Foo(["foo", "bar"])); /// /// ``` /// /// ### Motivating example /// /// ```rust /// use konst::polymorphism::{ /// HasTypeWitness, /// MakeTypeWitness, /// TypeEq, /// TypeWitnessTypeArg, /// type_eq_projection_fn, /// }; /// /// fn main() { /// assert_eq!(Foo(3, false).transform(), Foo(13, false)); /// assert_eq!(Foo("hello", "world").transform(), Foo("mapped", "world")); /// } /// /// #[derive(Debug, PartialEq)] /// struct Foo(T, U); /// /// // This macro invocation generates: /// // const fn project_to_foo( /// // _: TypeEq, /// // ) -> TypeEq, Foo> /// type_eq_projection_fn!{ /// // The `Copy` bound needs to be wrapped in parentheses in `U: (Copy)` to /// // simplify parsing of trait bounds in the generic parameter list. /// // /// // note: trait bounds are written normally in where clauses, /// // they must be unparenthesized. /// const fn project_to_foo(T) -> Foo /// } /// /// impl Foo { /// const fn transform<'a>(self) -> Foo /// where /// T: Copy + HasTypeWitness>, /// { /// match T::WITNESS { /// TheWitness::U8(te) => { /// // the type annotation is just for the reader /// let te: TypeEq, Foo> = project_to_foo(te); /// let bar: Foo = te.to_right(self); /// /// te.to_left(Foo(bar.0 + 10, bar.1)) /// } /// TheWitness::Str(te) => { /// // the type annotation is just for the reader /// let te: TypeEq, Foo<&str, U>> = project_to_foo(te); /// te.to_left(Foo("mapped", self.1)) /// } /// } /// } /// } /// /// // A type witness, a pattern documented in `konst::docs::type_witnesses` /// // /// // Simply put, type witnesses emulate matching over a range of types /// // (not values of those types, the types themselves). /// enum TheWitness<'a, T> { /// U8(TypeEq), /// Str(TypeEq), /// } /// /// impl TypeWitnessTypeArg for TheWitness<'_, T> { /// type Arg = T; /// } /// /// impl MakeTypeWitness for TheWitness<'_, u8> { /// const MAKE: Self = Self::U8(TypeEq::NEW); /// } /// /// impl<'a> MakeTypeWitness for TheWitness<'a, &'a str> { /// const MAKE: Self = Self::Str(TypeEq::NEW); /// } /// /// ``` /// /// ### Syntax /// /// This example demonstrates all the syntax that this macro supports. /// /// ```rust /// # use std::fmt::Debug; /// # use konst::polymorphism::type_eq_projection_fn; /// # /// # extern crate self as foo; /// # /// # #[derive(Debug, PartialEq, Clone)] /// # pub struct Ty<'a, 'b: 'a, U: 'a + Debug, const N: usize>(&'a &'b [U; N]); /// # /// // This macro invocation generates this function: /// // /// // pub const fn project<'a, 'b, L, R, const N: usize>( /// // _: TypeEq /// // ) -> TypeEq<::foo::Ty<'a, 'b, L, N>, ::foo::Ty<'a, 'b, R, N>> /// // where /// // 'b: 'a, /// // L: 'b + Debug, /// // R: 'b + Debug, /// // [u32; N]: 'a + core::fmt::Debug /// type_eq_projection_fn!{ /// /// Documentation for the generated function /// // /// // Without the `const` qualifier, the generated function is non-`const`. /// // /// // `T` must be both the function parameter, and in the return type. /// pub const fn project(T) -> ::foo::Ty< /// 'a, /// 'b: 'a, /// // trait bounds in the type parameter list must be parenthesized /// T: ('b + Debug), /// const N: usize, /// > /// where /// // trait bounds in the where clause are unparenthesized /// [u32; N]: 'a + core::fmt::Debug, /// } /// # fn main(){} /// ``` /// pub use konst_kernel::type_eq_projection_fn;konst-0.3.16/src/polymorphism.rs000064400000000000000000000012111046102023000147430ustar 00000000000000//! Miscelaneous items used for emulating polymorphism without trait methods. //! //! # `typewit` //! //! This crate uses [`typewit`] for emulating trait based polymorphism in const fns, //! because trait methods cannot be called in `const fn`s on stable(as of Rust 1.69.0) //! /// Markers used to classify types, used as `Kind` associated types. pub mod kinds { #[doc(inline)] pub use konst_kernel::polymorphism::kinds::*; } #[doc(no_inline)] pub use typewit::{ self, simple_type_witness, type_fn, CallFn, HasTypeWitness, MakeTypeWitness, TypeEq, TypeFn, TypeWitnessTypeArg, }; include! {"polymorphism/type_eq_projection_fn.rs"} konst-0.3.16/src/primitive/cmp.rs000064400000000000000000000033141046102023000147760ustar 00000000000000use core::cmp::Ordering; macro_rules! declare_int_cmp_fn { ( ($type:ty, ($cmp_fn_name:ident)) docs( $docs_eq:expr, $docs_cmp:expr, ) ) => { crate::__delegate_const_ord! { #[doc = $docs_cmp] pub const fn $cmp_fn_name(copy left: $type, right: $type) -> Ordering { cmp_int!(left, right) } } }; } __declare_fns_with_docs! { (u8, (cmp_u8)) (u16, (cmp_u16)) (u32, (cmp_u32)) (u64, (cmp_u64)) (u128, (cmp_u128)) (usize, (cmp_usize)) (i8, (cmp_i8)) (i16, (cmp_i16)) (i32, (cmp_i32)) (i64, (cmp_i64)) (i128, (cmp_i128)) (isize, (cmp_isize)) (bool, (cmp_bool)) (char, (cmp_char)) docs(default) macro = declare_int_cmp_fn!(), } __declare_fns_with_docs! { (Option, (eq_option_u8, cmp_option_u8)) (Option, (eq_option_i8, cmp_option_i8)) (Option, (eq_option_u16, cmp_option_u16)) (Option, (eq_option_i16, cmp_option_i16)) (Option, (eq_option_u32, cmp_option_u32)) (Option, (eq_option_i32, cmp_option_i32)) (Option, (eq_option_u64, cmp_option_u64)) (Option, (eq_option_i64, cmp_option_i64)) (Option, (eq_option_u128, cmp_option_u128)) (Option, (eq_option_i128, cmp_option_i128)) (Option, (eq_option_usize, cmp_option_usize)) (Option, (eq_option_isize, cmp_option_isize)) (Option, (eq_option_bool, cmp_option_bool)) (Option, (eq_option_char, cmp_option_char)) docs(default) macro = __impl_option_cmp_fns!( params(l, r) eq_comparison = l == r, cmp_comparison = cmp_int!(l, r), parameter_copyability = copy, ), } konst-0.3.16/src/primitive/parse.rs000064400000000000000000000246271046102023000153430ustar 00000000000000use crate::Parser; macro_rules! define_parse_methods { ( $(( $(#[$attr:meta])* fn $fn_name:ident, $parsing:ty, $err:ident $(,)? ))* ) => ( $( define_parse_methods_inner!{ concat!( "Parses a `", stringify!($parsing), "` from a `&str`.\n\n", "This returns an `Err` if the string would not successfully `.parse()` into a `", stringify!($parsing), "`.\n\n", "To parse a `", stringify!($parsing), "` from only part of a string, you can use [`Parser::parse_", stringify!($parsing), "`](../parsing/struct.Parser.html#method.parse_", stringify!($parsing), ")", ".\n\n", ), concat!( "Like [`", stringify!($fn_name), "`](./fn.", stringify!($fn_name),".html)", "but takes a `&[u8]` argument." ), $(#[$attr])*, $fn_name, $parsing, $err, } )* ); } macro_rules! define_parse_methods_inner{ ( $s_docs:expr, $b_docs:expr, $(#[$attr:meta])*, $fn_name:ident, $parsing:ty, $err:ident, ) => { #[doc = $s_docs] $(#[$attr])* #[inline] #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] pub const fn $fn_name(s: &str) -> Result<$parsing, $err> { match Parser::new(s).$fn_name() { Ok((num, parser)) if parser.is_empty() => Ok(num), _ => Err($err { _priv: (), }), } } } } define_parse_methods! { ( /// # Const stabilization /// /// The [equivalent std function](u128::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// ```rust /// use konst::{ /// primitive::{ParseIntResult, parse_u128}, /// unwrap_ctx, /// }; /// /// const I: ParseIntResult = parse_u128("1000"); /// /// assert_eq!(I, Ok(1000)); /// assert_eq!(parse_u128("123"), Ok(123)); /// assert_eq!(parse_u128("0"), Ok(0)); /// /// // This is how you can unwrap integers parsed from strings, at compile-time. /// const I2: u128 = unwrap_ctx!(parse_u128("1000")); /// assert_eq!(I2, 1000); /// /// assert!(parse_u128("-1").is_err()); /// assert!(parse_u128("100A").is_err()); /// assert!(parse_u128("-").is_err()); /// /// ``` /// fn parse_u128, u128, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](i128::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// ```rust /// use konst::{ /// primitive::{ParseIntResult, parse_i128}, /// unwrap_ctx, /// }; /// /// const I: ParseIntResult = parse_i128("1234"); /// /// assert_eq!(I, Ok(1234)); /// assert_eq!(parse_i128("123"), Ok(123)); /// assert_eq!(parse_i128("0"), Ok(0)); /// assert_eq!(parse_i128("-1"), Ok(-1)); /// /// // This is how you can unwrap integers parsed from strings, at compile-time. /// const I2: i128 = unwrap_ctx!(parse_i128("1234")); /// assert_eq!(I2, 1234); /// /// assert!(parse_i128("100A").is_err()); /// assert!(parse_i128("-A").is_err()); /// assert!(parse_i128("-").is_err()); /// /// ``` /// fn parse_i128, i128, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](u64::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `u128`](./fn.parse_u128.html). fn parse_u64, u64, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](i64::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `i128`](./fn.parse_i128.html). fn parse_i64, i64, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](u32::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `u128`](./fn.parse_u128.html). fn parse_u32, u32, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](i32::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `i128`](./fn.parse_i128.html). fn parse_i32, i32, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](u16::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `u128`](./fn.parse_u128.html). fn parse_u16, u16, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](i16::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `i128`](./fn.parse_i128.html). fn parse_i16, i16, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](u8::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `u128`](./fn.parse_u128.html). fn parse_u8, u8, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](i8::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `i128`](./fn.parse_i128.html). fn parse_i8, i8, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](usize::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `u128`](./fn.parse_u128.html). fn parse_usize, usize, ParseIntError ) ( /// # Const stabilization /// /// The [equivalent std function](isize::from_str_radix), /// was const-stabilized in Rust 1.82.0. /// /// # Example /// /// For an example of how to use this function, you can look at /// [the one for `i128`](./fn.parse_i128.html). fn parse_isize, isize, ParseIntError ) ( /// # Example /// /// ```rust /// use konst::{ /// primitive::{ParseBoolResult, parse_bool}, /// unwrap_ctx, /// }; /// /// const T: ParseBoolResult = parse_bool("true"); /// const F: ParseBoolResult = parse_bool("false"); /// /// assert_eq!(T, Ok(true)); /// assert_eq!(F, Ok(false)); /// /// // This is how you can unwrap bools parsed from strings, at compile-time. /// const T2: bool = unwrap_ctx!(parse_bool("true")); /// const F2: bool = unwrap_ctx!(parse_bool("false")); /// /// assert_eq!(T2, true); /// assert_eq!(F2, false); /// /// assert!(parse_bool("0").is_err()); /// assert!(parse_bool("FALSE").is_err()); /// /// /// ``` /// fn parse_bool, bool, ParseBoolError ) } //////////////////////////////////////////////////////////////////////////////// /// An alias for `Result` #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] pub type ParseIntResult = Result; /// An alias for `Result` #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] pub type ParseBoolResult = Result; //////////////////////////////////////////////////////////////////////////////// use core::fmt::{self, Display}; /// The error returned by integer-parsing methods. #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct ParseIntError { _priv: (), } impl Display for ParseIntError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("could not parse an integer") } } impl ParseIntError { /// Panics with this error as the message pub const fn panic(&self) -> ! { panic!("could not parse an integer") } } //////////////////////////////////////////////////////////////////////////////// /// The error returned by bool-parsing methods. #[cfg(feature = "parsing")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))] #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct ParseBoolError { _priv: (), } impl Display for ParseBoolError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("could not parse a bool") } } impl ParseBoolError { /// Panics with this error as the message pub const fn panic(&self) -> ! { panic!("could not parse a bool"); } } konst-0.3.16/src/primitive.rs000064400000000000000000000004671046102023000142250ustar 00000000000000//! `const fn` equivalents of primitive type methods. /// `const fn`s for comparing primitive types for equality and ordering. #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; #[cfg(feature = "parsing")] mod parse; #[cfg(feature = "parsing")] pub use parse::*; konst-0.3.16/src/ptr.rs000064400000000000000000000172121046102023000130160ustar 00000000000000//! Const equivalents of raw pointer and [`NonNull`](core::ptr::NonNull) methods. //! //! # Removed in 0.3.0 //! //! These functions were removed in 0.3.0 because there is an equivalent //! const fn in the standard library: //! //! - `deref`: raw pointers can be dereferenced since Rust 1.58.0 //! //! - `deref_mut`: Rust 1.83.0 allows dereferencing mutable pointers. //! use core::ptr::NonNull; /// Const equivalent of /// [`<*const>::as_ref`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref) /// /// # Safety /// /// This function has the same safety requirements as /// [`<*const T>::as_ref`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety) /// /// # Example /// /// ```rust /// use konst::ptr; /// /// use core::ptr::null; /// /// const NONE: Option<&u8> = unsafe{ ptr::as_ref(null()) }; /// const SOME: Option<&u8> = unsafe{ ptr::as_ref(&100) }; /// /// assert_eq!(NONE, None); /// assert_eq!(SOME, Some(&100)); /// /// /// ``` pub const unsafe fn as_ref<'a, T: ?Sized>(ptr: *const T) -> Option<&'a T> { core::mem::transmute(ptr) } /// Const equivalent of /// [`<*const>::as_mut`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut) /// /// # Safety /// /// This function has the same safety requirements as /// [`<*mut T>::as_mut`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety-13). /// /// # Example /// /// ```rust /// use konst::ptr; /// /// assert_eq!(ARR, [83, 91, 104]); /// /// const ARR: [u8; 3] = unsafe { /// let mut arr = [13, 21, 34]; /// mutate(&mut arr[0]); /// mutate(&mut arr[1]); /// mutate(&mut arr[2]); /// mutate(std::ptr::null_mut()); // no-op /// arr /// }; /// /// const unsafe fn mutate(x: *mut u8) { /// if let Some(mutt) = ptr::as_mut(x) { /// *mutt += 70; /// } /// } /// ``` #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const unsafe fn as_mut<'a, T: ?Sized>(ptr: *mut T) -> Option<&'a mut T> { core::mem::transmute(ptr) } /// Const equivalent of /// [`<*const T>::is_null`](https://doc.rust-lang.org/std/primitive.pointer.html#method.is_null) /// /// # Example /// /// ```rust /// use konst::ptr; /// /// use core::ptr::null; /// /// const NULL_IS_NULL: bool = ptr::is_null(null::()); /// const REFF_IS_NULL: bool = ptr::is_null(&100); /// /// assert_eq!(NULL_IS_NULL, true); /// assert_eq!(REFF_IS_NULL, false); /// /// /// ``` #[deprecated( since = "0.3.16", note = "unsound for out of bounds pointers" )] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub const fn is_null(ptr: *const T) -> bool { unsafe { matches!( core::mem::transmute::<*const T, Option>>(ptr), None ) } } /// Const equivalents of [`NonNull`](core::ptr::NonNull) methods. pub mod nonnull { use core::ptr::NonNull; /// Const equivalent of [`NonNull::new`](core::ptr::NonNull::new). /// /// # Example /// /// ```rust /// use konst::ptr::nonnull; /// /// use core::ptr::{NonNull, null_mut}; /// /// const NONE: Option> = nonnull::new(null_mut()); /// const SOME: Option> = nonnull::new(&100 as *const _ as *mut _); /// /// assert!(NONE.is_none()); /// assert_eq!(SOME.map(|x|unsafe{*x.as_ptr()}), Some(100)); /// /// /// ``` #[deprecated( since = "0.3.16", note = "unsound for out of bounds pointers" )] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub const fn new(ptr: *mut T) -> Option> { unsafe { core::mem::transmute(ptr) } } /// Const equivalent of [`NonNull::as_ref`](core::ptr::NonNull::as_ref). /// /// # Safety /// /// This has [the same safety requirements as `NonNull::as_ref` /// ](https://doc.rust-lang.org/1.55.0/core/ptr/struct.NonNull.html#safety-3) /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.73.0. /// /// # Example /// /// ```rust /// use konst::ptr::nonnull; /// /// use core::{ /// ptr::NonNull, /// marker::PhantomData, /// }; /// /// const A: NonNull = nonnull::from_ref(&3); /// const A_REF: &u8 = unsafe{ nonnull::as_ref(A) }; /// assert_eq!(A_REF, &3); /// /// const B: NonNull = nonnull::from_ref("hello"); /// const B_REF: &str = unsafe{ nonnull::as_ref(B) }; /// assert_eq!(B_REF, "hello"); /// /// ``` /// pub const unsafe fn as_ref<'a, T: ?Sized>(ptr: NonNull) -> &'a T { &*(ptr.as_ptr() as *const T) } /// Const equivalent of [`NonNull::as_mut`](core::ptr::NonNull::as_mut). /// /// # Safety /// /// This has [the same safety requirements as `NonNull::as_mut` /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#safety-4) /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::ptr::nonnull; /// /// use core::ptr::NonNull; /// /// assert_eq!(TUP, (13, 15, 18)); /// /// const TUP: (u8, u8, u8) = unsafe { /// let mut tuple = (3, 5, 8); /// mutate(nonnull::from_mut(&mut tuple.0)); /// mutate(nonnull::from_mut(&mut tuple.1)); /// mutate(nonnull::from_mut(&mut tuple.2)); /// tuple /// }; /// /// const unsafe fn mutate(x: NonNull) { /// *nonnull::as_mut(x) += 10; /// } /// /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const unsafe fn as_mut<'a, T: ?Sized>(ptr: NonNull) -> &'a mut T { &mut *ptr.as_ptr() } /// Const equivalent of /// [` as From<&T>>::from` /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#impl-From%3C%26%27_%20T%3E) /// /// # Example /// /// ```rust /// use konst::ptr::nonnull; /// /// use core::ptr::NonNull; /// /// const H: NonNull = nonnull::from_ref("hello"); /// const W: NonNull = nonnull::from_ref("world"); /// /// unsafe{ /// assert_eq!(H.as_ref(), "hello"); /// assert_eq!(W.as_ref(), "world"); /// } /// ``` pub const fn from_ref(reff: &T) -> NonNull { // SAFETY: `&T` is non-null, which is all that `NonNull::new_unchecked` requires unsafe { NonNull::new_unchecked(reff as *const _ as *mut _) } } /// Const equivalent of /// [` as From<&mut T>>::from` /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#impl-From%3C%26%27_%20mut%20T%3E) /// /// # Example /// /// ```rust /// use konst::ptr::nonnull as nn; /// /// use core::ptr::NonNull; /// /// assert_eq!(ARR, (5, 8, 3)); /// /// const ARR: (u8, u8, u8) = unsafe { /// let mut tup = (3, 5, 8); /// swap(nn::from_mut(&mut tup.0), nn::from_mut(&mut tup.1)); /// swap(nn::from_mut(&mut tup.1), nn::from_mut(&mut tup.2)); /// tup /// }; /// /// const unsafe fn swap(x: NonNull, y: NonNull) { /// let xm = nn::as_mut(x); /// let ym = nn::as_mut(y); /// let tmp = *xm; /// *xm = *ym; /// *ym = tmp; /// } /// /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn from_mut(mutt: &mut T) -> NonNull { // SAFETY: `&mut T` is non-null, which is all that `NonNull::new_unchecked` requires unsafe { NonNull::new_unchecked(mutt) } } } konst-0.3.16/src/range/cmp.rs000064400000000000000000000053231046102023000140640ustar 00000000000000use core::ops::{Range, RangeInclusive}; use crate::cmp::{CmpWrapper, ConstCmp, IsAConstCmp, IsStdKind}; macro_rules! shared_range_impls { ($type:ty, $eq_fn_name:ident) => { impl ConstCmp for $type { type Kind = IsStdKind; } impl CmpWrapper<$type> { /// Compares `self` and `other` for equality. #[inline(always)] pub const fn const_eq(&self, other: &$type) -> bool { $eq_fn_name(&self.0, other) } } }; } macro_rules! declare_range_cmp_fns { ( ($type:ty, ($eq_fn_name:ident)) docs( $docs_eq:expr, $docs_cmp:expr,) ) => { shared_range_impls! {$type, $eq_fn_name} impl IsAConstCmp { /// #[inline(always)] pub const fn coerce(self, range: &$type) -> CmpWrapper<$type> { CmpWrapper(Range { start: range.start, end: range.end, }) } } __delegate_const_eq! { skip_coerce; for['a,] #[doc = $docs_eq] pub const fn $eq_fn_name(ref left: &'a $type, right: &'a $type) -> bool { left.start == right.start && left.end == right.end } } }; } __declare_fns_with_docs! { (Range, (eq_range_u8)) (Range, (eq_range_u16)) (Range, (eq_range_u32)) (Range, (eq_range_u64)) (Range, (eq_range_u128)) (Range, (eq_range_usize)) (Range, (eq_range_char)) docs(default) macro = declare_range_cmp_fns!(), } macro_rules! declare_rangeinclusive_cmp_fns { ( ($type:ty, ($eq_fn_name:ident)) docs( $docs_eq:expr, $docs_cmp:expr,) ) => { shared_range_impls! {$type, $eq_fn_name} impl IsAConstCmp { /// #[inline(always)] pub const fn coerce(self, range: &$type) -> CmpWrapper<$type> { CmpWrapper(RangeInclusive::new(*range.start(), *range.end())) } } #[doc = $docs_eq] pub const fn $eq_fn_name(left: &$type, right: &$type) -> bool { *left.start() == *right.start() && *left.end() == *right.end() } }; } __declare_fns_with_docs! { (RangeInclusive, (eq_rangeinc_u8,)) (RangeInclusive, (eq_rangeinc_u16)) (RangeInclusive, (eq_rangeinc_u32)) (RangeInclusive, (eq_rangeinc_u64)) (RangeInclusive, (eq_rangeinc_u128)) (RangeInclusive, (eq_rangeinc_usize)) (RangeInclusive, (eq_rangeinc_char)) docs(default) macro = declare_rangeinclusive_cmp_fns!(), } konst-0.3.16/src/range.rs000064400000000000000000000035311046102023000133040ustar 00000000000000//! `const fn` equivalents of range methods. /// `const fn`s for comparing range for equality and ordering. #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; /// Const-iterator for [`Range`](core::ops::Range) /// /// This is constructed like this: /// ```rust /// # let _ = /// konst::iter::into_iter!(0..10) /// # ; /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::range_into_iter::RangeIter; /// Reversed const-iterator for [`Range`](core::ops::Range) /// /// /// This is constructed like this: /// ```rust /// # let _ = /// konst::iter::into_iter!(0..10).rev() /// # ; /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::range_into_iter::RangeIterRev; /// Const-iterator for [`RangeInclusive`](core::ops::RangeInclusive) /// /// This is constructed like this: /// ```rust /// # let _ = /// konst::iter::into_iter!(0..=10) /// # ; /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::range_into_iter::RangeInclusiveIter; /// Reversed const-iterator for [`RangeInclusive`](core::ops::RangeInclusive) /// /// This is constructed like this: /// ```rust /// # let _ = /// konst::iter::into_iter!(0..=10).rev() /// # ; /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::range_into_iter::RangeInclusiveIterRev; /// Const-iterator for [`RangeFrom`](core::ops::RangeFrom) /// /// This is constructed like this: /// ```rust /// # let _ = /// konst::iter::into_iter!(0..) /// # ; /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::range_into_iter::RangeFromIter; konst-0.3.16/src/result.rs000064400000000000000000000214501046102023000135260ustar 00000000000000//! `const` equivalents of `Result` methods. /// For unwrapping `Result`s in const contexts with some error message. /// /// The error type must have a method with this signature: /// /// ```rust /// # struct Foo; /// # impl Foo { /// pub const fn panic(&self) -> ! { /// # loop{} /// # } /// # } /// ``` /// /// All the errors from this crate can be used with this macro. /// /// # Example /// /// ### Basic /// #[cfg_attr(feature = "parsing", doc = "```rust")] #[cfg_attr(not(feature = "parsing"), doc = "```ignore")] /// use konst::{Parser, unwrap_ctx}; /// /// let mut parser = Parser::new("hello world"); /// /// parser = unwrap_ctx!(parser.strip_prefix("hello ")); /// /// assert_eq!(parser.remainder(), "world"); /// /// ``` /// /// ### Defining error type /// /// ```rust /// use konst::unwrap_ctx; /// /// const UNWRAPPED: u32 = { /// let res: Result = Ok(100); /// unwrap_ctx!(res) /// }; /// /// assert_eq!(UNWRAPPED, 100); /// /// /// use std::fmt::{self, Display}; /// /// #[derive(Debug, Clone, PartialEq)] /// pub struct FooError(usize); /// /// impl FooError { /// pub const fn panic(&self) -> ! { /// panic!("Foo error") /// /// // Alternatively, using the `const_panic` crate: /// // /// // const_panic::concat_panic!("Foo errored at offset: ", self.0) /// } /// } /// /// impl Display for FooError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// fmt::Debug::fmt(self, f) /// } /// } /// /// impl std::error::Error for FooError {} /// /// ``` /// /// If `res` was an error instead, this is the error message you would see: /// /// ```text /// error[E0080]: evaluation of constant value failed /// --> src/result.rs:55:9 /// | /// 9 | unwrap_ctx!(res) /// | ---------------- inside `UNWRAPPED` at result_macros_.rs:6:35 /// ... /// 23 | panic!("Foo error") /// | ^^^^^^^^^^^^^^^^^^^ /// | | /// | the evaluated program panicked at 'Foo error', src/result.rs:23:9 /// | inside `FooError::panic` /// /// ``` /// /// [`Parser`]: ../parsing/struct.Parser.html #[doc(inline)] pub use konst_kernel::unwrap_ctx; /// A const equivalent of [`Result::unwrap_or`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[u32] = &[ /// result::unwrap_or!(Res::Ok(3), 5), /// result::unwrap_or!(Res::Err(8), 13), /// ]; /// /// assert_eq!(ARR, &[3, 13]); /// /// ``` /// #[doc(inline)] pub use konst_kernel::res_unwrap_or as unwrap_or; /// A const equivalent of [`Result::unwrap_or_else`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[u32] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Err. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::unwrap_or_else!(Res::Ok(3), |_| loop{}), /// result::unwrap_or_else!(Res::Err(8), |x| x + 5), /// /// // You can also pass functions /// result::unwrap_or_else!(Res::Ok(21), add_34), /// result::unwrap_or_else!(Res::Err(55), add_34), /// ]; /// /// assert_eq!(ARR, &[3, 13, 21, 89]); /// /// const fn add_34(n: u32) -> u32 { /// n + 34 /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_unwrap_or_else as unwrap_or_else; /// Returns the error in the `Err` variant, /// otherwise runs a closure/function with the value in the `Ok` variant. /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[u32] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Ok. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::unwrap_err_or_else!(Res::Ok(3), |x| x + 2), /// result::unwrap_err_or_else!(Res::Err(8), |_| loop{}), /// /// // You can also pass functions /// result::unwrap_err_or_else!(Res::Ok(16), add_34), /// result::unwrap_err_or_else!(Res::Err(55), add_34), /// ]; /// /// assert_eq!(ARR, &[5, 8, 50, 55]); /// /// const fn add_34(n: u32) -> u32 { /// n + 34 /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_unwrap_err_or_else as unwrap_err_or_else; /// A const equivalent of [`Result::ok`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Option] = &[ /// result::ok!(Res::Ok(3)), /// result::ok!(Res::Err(8)), /// ]; /// /// assert_eq!(ARR, &[Some(3), None]); /// /// ``` /// #[doc(inline)] pub use konst_kernel::res_ok as ok; /// A const equivalent of [`Result::err`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Option] = &[ /// result::err!(Res::Ok(3)), /// result::err!(Res::Err(8)), /// ]; /// /// assert_eq!(ARR, &[None, Some(8)]); /// /// ``` /// #[doc(inline)] pub use konst_kernel::res_err as err; /// A const equivalent of [`Result::map`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Res] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Ok. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::map!(Res::Ok(3), |x| x + 2), /// result::map!(Res::Err(8), |_| loop{}), /// /// // You can also pass functions /// result::map!(Res::Ok(16), add_34), /// result::map!(Res::Err(55), add_34), /// ]; /// /// assert_eq!(ARR, &[Ok(5), Err(8), Ok(50), Err(55)]); /// /// const fn add_34(n: u32) -> u32 { /// n + 34 /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_map as map; /// A const equivalent of [`Result::map_err`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Res] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Ok. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::map_err!(Res::Ok(3), |_| loop{}), /// result::map_err!(Res::Err(8), |x| x + 5), /// /// // You can also pass functions /// result::map_err!(Res::Ok(16), add_34), /// result::map_err!(Res::Err(55), add_34), /// ]; /// /// assert_eq!(ARR, &[Ok(3), Err(13), Ok(16), Err(89)]); /// /// const fn add_34(n: u32) -> u32 { /// n + 34 /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_map_err as map_err; /// A const equivalent of [`Result::and_then`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Res] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Ok. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::and_then!(Res::Ok(1), |x| Ok(x + 2)), /// result::and_then!(Res::Ok(10), |x| Err(x + 4)), /// result::and_then!(Res::Err(20), |_| loop{}), /// /// // You can also pass functions /// result::and_then!(Res::Ok(40), add_2), /// result::and_then!(Res::Ok(40), add_5), /// result::and_then!(Res::Err(60), add_5), /// ]; /// /// assert_eq!(ARR, &[Ok(3), Err(14), Err(20), Ok(42), Err(45), Err(60)]); /// /// const fn add_2(n: u32) -> Res { /// Ok(n + 2) /// } /// const fn add_5(n: u32) -> Res { /// Err(n + 5) /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_and_then as and_then; /// A const equivalent of [`Result::or_else`] /// /// # Example /// /// ```rust /// use konst::result; /// /// // Necessary for type inference reasons. /// type Res = Result; /// /// const ARR: &[Res] = &[ /// // You can use a closure-like syntax to run code when the Result argument is Err. /// // `return` inside the "closure" returns from the function where this macro is called. /// result::or_else!(Res::Ok(1), |_| loop{}), /// result::or_else!(Res::Err(20), |x| Ok(x + 5)), /// result::or_else!(Res::Err(20), |x| Err(x + 7)), /// /// // You can also pass functions /// result::or_else!(Res::Ok(40), add_2), /// result::or_else!(Res::Err(60), add_2), /// result::or_else!(Res::Err(60), add_5), /// ]; /// /// assert_eq!(ARR, &[Ok(1), Ok(25), Err(27), Ok(40), Ok(62), Err(65)]); /// /// const fn add_2(n: u32) -> Res { /// Ok(n + 2) /// } /// const fn add_5(n: u32) -> Res { /// Err(n + 5) /// } /// ``` /// #[doc(inline)] pub use konst_kernel::res_or_else as or_else; konst-0.3.16/src/root_module_macros.rs000064400000000000000000000006221046102023000161020ustar 00000000000000/// For loop over a range /// /// # Example /// /// ```rust /// use konst::for_range; /// /// const LEN: usize = 10; /// const ARR: [u32; LEN] = { /// let mut ret = [1; LEN]; /// for_range!{i in 2..LEN => /// ret[i] = ret[i - 1] + ret[i - 2]; /// } /// ret /// }; /// /// assert_eq!(ARR, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]); /// ``` /// pub use konst_kernel::for_range;konst-0.3.16/src/slice/bytes_pattern.rs000064400000000000000000000066101046102023000161730ustar 00000000000000use crate::{ chr, polymorphism::{HasTypeWitness, MakeTypeWitness, TypeEq, TypeWitnessTypeArg}, }; /// A byte slice pattern. /// /// Types that implement this trait can be used to search into a byte slice. /// /// This trait can only be implemented in the `konst` crate. /// pub trait BytesPattern: HasTypeWitness> { #[doc(hidden)] type __Normalized: ?Sized; } #[non_exhaustive] pub enum BytesPatternInput> { Str(TypeEq, TypeEq<*const P::__Normalized, *const [u8]>), Bytes(TypeEq, TypeEq<*const P::__Normalized, *const [u8]>), Array( TypeEq, TypeEq<*const P::__Normalized, *const [u8]>, ), Char( TypeEq, TypeEq<*const P::__Normalized, *const chr::Utf8Encoded>, ), } impl TypeWitnessTypeArg for BytesPatternInput where Arg: ?Sized + BytesPattern, { type Arg = Arg; } impl MakeTypeWitness for BytesPatternInput<0, str> { const MAKE: Self = BytesPatternInput::Str(TypeEq::NEW, TypeEq::NEW); } impl BytesPattern<0> for str { #[doc(hidden)] type __Normalized = [u8]; } impl MakeTypeWitness for BytesPatternInput<0, [u8]> { const MAKE: Self = BytesPatternInput::Bytes(TypeEq::NEW, TypeEq::NEW); } impl BytesPattern<0> for [u8] { #[doc(hidden)] type __Normalized = [u8]; } impl MakeTypeWitness for BytesPatternInput { const MAKE: Self = BytesPatternInput::Array(TypeEq::NEW, TypeEq::NEW); } impl BytesPattern for [u8; N] { #[doc(hidden)] type __Normalized = [u8]; } impl MakeTypeWitness for BytesPatternInput<0, char> { const MAKE: Self = BytesPatternInput::Char(TypeEq::NEW, TypeEq::NEW); } impl BytesPattern<0> for char { #[doc(hidden)] type __Normalized = chr::Utf8Encoded; } #[derive(Copy, Clone)] pub(crate) enum PatternNorm<'a, const N: usize, P> where P: ?Sized + BytesPattern, { Bytes { val: &'a [u8], ten: TypeEq<*const P::__Normalized, *const [u8]>, }, Char { val: chr::Utf8Encoded, ten: TypeEq<*const P::__Normalized, *const chr::Utf8Encoded>, }, } impl<'a, const N: usize, P> PatternNorm<'a, N, P> where P: ?Sized + BytesPattern, { pub(crate) const fn new(pattern: &'a P) -> Self { match P::WITNESS { BytesPatternInput::Str(te, ten) => { let val: &'a [u8] = te.in_ref().to_right(pattern).as_bytes(); PatternNorm::Bytes { val, ten } } BytesPatternInput::Bytes(te, ten) => { let val: &'a [u8] = te.in_ref().to_right(pattern); PatternNorm::Bytes { val, ten } } BytesPatternInput::Array(te, ten) => { let val: &'a [u8] = te.in_ref().to_right(pattern); PatternNorm::Bytes { val, ten } } BytesPatternInput::Char(te, ten) => { let val: &'a char = te.in_ref().to_right(pattern); let val = chr::encode_utf8(*val); PatternNorm::Char { val, ten } } } } pub(crate) const fn as_bytes(&self) -> &[u8] { match self { PatternNorm::Bytes { val, ten } => ten.reachability_hint(val), PatternNorm::Char { val, ten } => ten.reachability_hint(val.as_bytes()), } } } konst-0.3.16/src/slice/cmp.rs000064400000000000000000000067161046102023000140760ustar 00000000000000#[doc(inline)] pub use crate::slice::{ cmp_bytes as cmp_slice_u8, cmp_option_bytes as cmp_option_slice_u8, eq_bytes as eq_slice_u8, eq_option_bytes as eq_option_slice_u8, }; use core::cmp::Ordering; __declare_slice_cmp_fns! { import_path = "konst", (,,, u16, eq_slice_u16, cmp_slice_u16,) (,,, u32, eq_slice_u32, cmp_slice_u32,) (,,, u64, eq_slice_u64, cmp_slice_u64,) (,,, u128, eq_slice_u128, cmp_slice_u128,) (,,, usize, eq_slice_usize, cmp_slice_usize,) (,,, i8, eq_slice_i8, cmp_slice_i8,) (,,, i16, eq_slice_i16, cmp_slice_i16,) (,,, i32, eq_slice_i32, cmp_slice_i32,) (,,, i64, eq_slice_i64, cmp_slice_i64,) (,,, i128, eq_slice_i128, cmp_slice_i128,) (,,, isize, eq_slice_isize, cmp_slice_isize,) (,,, bool, eq_slice_bool, cmp_slice_bool,) (,,, char, eq_slice_char, cmp_slice_char,) } __delegate_const_eq! { skip_coerce; /// Compares two `&[&str]` for equality. pub const fn eq_slice_str(ref l: &[&str], r: &[&str]) -> bool { crate::const_eq_for!(slice; l, r, crate::eq_str) } } __delegate_const_ord! { skip_coerce; /// Compares two `&[&str]`, returning the order of `left` relative to `right`. pub const fn cmp_slice_str(ref left: &[&str], right: &[&str]) -> Ordering { crate::const_cmp_for!(slice; left, right, crate::cmp_str) } } __delegate_const_eq! { skip_coerce; /// Compares two `&[&[u8]]` for equality. pub const fn eq_slice_bytes(ref l: &[&[u8]], r: &[&[u8]]) -> bool { crate::const_eq_for!(slice; l, r, eq_slice_u8) } } __delegate_const_ord! { skip_coerce; /// Compares two `&[&[u8]]`, returning the order of `left` relative to `right`. pub const fn cmp_slice_bytes(ref left: &[&[u8]], right: &[&[u8]]) -> Ordering { crate::const_cmp_for!(slice; left, right, cmp_slice_u8) } } __declare_fns_with_docs! { (Option<&'a [u16]>, (eq_option_slice_u16, cmp_option_slice_u16)) (Option<&'a [u32]>, (eq_option_slice_u32, cmp_option_slice_u32)) (Option<&'a [u64]>, (eq_option_slice_u64, cmp_option_slice_u64)) (Option<&'a [u128]>, (eq_option_slice_u128, cmp_option_slice_u128)) (Option<&'a [usize]>, (eq_option_slice_usize, cmp_option_slice_usize)) (Option<&'a [i8]>, (eq_option_slice_i8, cmp_option_slice_i8)) (Option<&'a [i16]>, (eq_option_slice_i16, cmp_option_slice_i16)) (Option<&'a [i32]>, (eq_option_slice_i32, cmp_option_slice_i32)) (Option<&'a [i64]>, (eq_option_slice_i64, cmp_option_slice_i64)) (Option<&'a [i128]>, (eq_option_slice_i128, cmp_option_slice_i128)) (Option<&'a [isize]>, (eq_option_slice_isize, cmp_option_slice_isize)) (Option<&'a [bool]>, (eq_option_slice_bool, cmp_option_slice_bool)) (Option<&'a [char]>, (eq_option_slice_char, cmp_option_slice_char)) docs(default) macro = __impl_option_cmp_fns!( for['a,] params(l, r) eq_comparison = crate::cmp::CmpWrapper(l).const_eq(r), cmp_comparison = crate::cmp::CmpWrapper(l).const_cmp(r), parameter_copyability = copy, ), } __declare_fns_with_docs! { (Option<&'a [&'b str]>, (eq_option_slice_str, cmp_option_slice_str)) (Option<&'a [&'b [u8]]>, (eq_option_slice_bytes, cmp_option_slice_bytes)) docs(default) macro = __impl_option_cmp_fns!( for['a, 'b,] params(l, r) eq_comparison = crate::cmp::CmpWrapper(l).const_eq(r), cmp_comparison = crate::cmp::CmpWrapper(l).const_cmp(r), parameter_copyability = copy, ), } konst-0.3.16/src/slice/slice_as_chunks.rs000064400000000000000000000037761046102023000164570ustar 00000000000000use crate::slice; /// Const equivalent of /// [`<[T]>::as_chunks`](https://doc.rust-lang.org/std/primitive.slice.html#method.as_chunks) /// /// The equivalent std function is unstable as of Rust 1.83.0. /// /// # Panics /// /// Panics if `N == 0`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// let (arrs, rem) = slice::as_chunks::<_, 3>(&[2u32, 3, 5, 8, 13, 21, 34, 55]); /// /// assert_eq!(arrs, &[[2, 3, 5], [8, 13, 21]][..]); /// assert_eq!(rem, &[34, 55][..]) /// /// ``` #[track_caller] pub const fn as_chunks<'a, T, const N: usize>(this: &[T]) -> (&[[T; N]], &[T]) { assert!(N != 0, "chunk size must be non-zero"); let arrs_len = this.len() / N; let (arrs_in, rem) = slice::split_at(this, arrs_len * N); // SAFETY: `arrs_in` is a `&[T]` that is `arrs_len * N` long, // its layout is compatible with the `&[[T; N]]` that this produces. let arrs: &[[T; N]] = unsafe { core::slice::from_raw_parts(arrs_in.as_ptr() as *const [T; N], arrs_len) }; (arrs, rem) } /// Const equivalent of /// [`<[T]>::as_rchunks`](https://doc.rust-lang.org/std/primitive.slice.html#method.as_rchunks) /// /// The equivalent std function is unstable as of Rust 1.83.0. /// /// # Panics /// /// Panics if `N == 0`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// let (rem, arrs) = slice::as_rchunks::<_, 2>(&[2u32, 3, 5, 8, 13, 21, 34]); /// /// assert_eq!(rem, &[2][..]); /// assert_eq!(arrs, &[[3, 5], [8, 13], [21, 34]][..]); /// ``` #[track_caller] pub const fn as_rchunks<'a, T, const N: usize>(this: &[T]) -> (&[T], &[[T; N]]) { assert!(N != 0, "chunk size must be non-zero"); let arrs_len = this.len() / N; let rem_len = this.len() % N; let (rem, arrs_in) = slice::split_at(this, rem_len); // SAFETY: `arrs_in` is a `&[T]` that is `arrs_len * N` long, // its layout is compatible with the `&[[T; N]]` that this produces. let arrs: &[[T; N]] = unsafe { core::slice::from_raw_parts(arrs_in.as_ptr() as *const [T; N], arrs_len) }; (rem, arrs) } konst-0.3.16/src/slice/slice_concatenation.rs000064400000000000000000000013621046102023000173130ustar 00000000000000/// Macro equivalent of `<[&[T]]>::concat`, which takes a constant as an argument. /// /// This acts like a compile-time-evaluated version of this function: /// ```rust /// pub const fn slice_concat(slices: &'static [&'static [T]]) -> [T; LEN] /// where /// T: Copy /// # { [] } /// # const LEN: usize = 0; /// ``` /// /// Where `LEN` is the summed length of all inner slices. /// /// # Example /// /// ```rust /// use konst::slice::slice_concat; /// /// const S: &[&[u8]] = &[&[3, 5], &[8, 13, 21, 34]]; /// assert_eq!(slice_concat!(u8, S), [3, 5, 8, 13, 21, 34]); /// /// assert_eq!(slice_concat!(u8, &[]), []); /// /// assert_eq!(slice_concat!(u8, &[&[], &[1, 2, 3], &[4, 5]]), [1, 2, 3, 4, 5]); /// /// ``` pub use konst_kernel::slice_concat; konst-0.3.16/src/slice/slice_const_methods.rs000064400000000000000000001156551046102023000173520ustar 00000000000000use konst_kernel::{__slice_from_impl, __slice_up_to_impl}; use crate::slice::{BytesPattern, PatternNorm}; /// A const equivalent of `slice.get(index)` /// /// # Example /// /// ```rust /// use konst::slice; /// /// const FIBB: &[u16] = &[3, 5, 8]; /// /// const ELEM0: Option<&u16> = slice::get(FIBB, 0); /// const ELEM1: Option<&u16> = slice::get(FIBB, 1); /// const ELEM2: Option<&u16> = slice::get(FIBB, 2); /// const ELEM3: Option<&u16> = slice::get(FIBB, 3); /// /// assert_eq!(ELEM0, Some(&3)); /// assert_eq!(ELEM1, Some(&5)); /// assert_eq!(ELEM2, Some(&8)); /// assert_eq!(ELEM3, None); /// /// ``` #[inline] pub const fn get(slice: &[T], index: usize) -> Option<&T> { if slice.len() > index { Some(&slice[index]) } else { None } } /// A const equivalent of `slice.get_mut(index)` /// /// # Example /// /// ```rust /// use konst::slice; /// /// let mut fibb = [3, 5, 8]; /// /// assert_eq!(slice::get_mut(&mut fibb, 0), Some(&mut 3)); /// assert_eq!(slice::get_mut(&mut fibb, 1), Some(&mut 5)); /// assert_eq!(slice::get_mut(&mut fibb, 2), Some(&mut 8)); /// assert_eq!(slice::get_mut(&mut fibb, 3), None); /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn get_mut(slice: &mut [T], index: usize) -> Option<&mut T> { if slice.len() > index { Some(&mut slice[index]) } else { None } } /// A const equivalent of `&slice[start..]`. /// /// If `slice.len() < start`, this simply returns an empty slice. /// /// # Example /// /// ```rust /// use konst::slice::slice_from; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: &[u16] = slice_from(FIBB, 2); /// const FOUR: &[u16] = slice_from(FIBB, 4); /// const ALL: &[u16] = slice_from(FIBB, 0); /// const NONE: &[u16] = slice_from(FIBB, 1000); /// /// assert_eq!(TWO, &[8, 13, 21, 34, 55, 89]); /// assert_eq!(FOUR, &[21, 34, 55, 89]); /// assert_eq!(ALL, FIBB); /// assert_eq!(NONE, &[]); /// /// ``` pub use konst_kernel::slice::slice_from; /// A const equivalent of `&slice[..len]`. /// /// If `slice.len() < len`, this simply returns `slice` back. /// /// # Example /// /// ```rust /// use konst::slice::slice_up_to; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: &[u16] = slice_up_to(FIBB, 2); /// const FOUR: &[u16] = slice_up_to(FIBB, 4); /// const NONE: &[u16] = slice_up_to(FIBB, 0); /// const ALL: &[u16] = slice_up_to(FIBB, 1000); /// /// assert_eq!(TWO, &[3, 5]); /// assert_eq!(FOUR, &[3, 5, 8, 13]); /// assert_eq!(NONE, &[]); /// assert_eq!(ALL, FIBB); /// /// ``` pub use konst_kernel::slice::slice_up_to; /// A const equivalent of `&slice[start..end]`. /// /// If `start >= end ` or `slice.len() < start `, this returns an empty slice. /// /// If `slice.len() < end`, this returns the slice from `start`. /// /// # Alternatives /// /// For a const equivalent of `&slice[start..]` there's [`slice_from`]. /// /// For a const equivalent of `&slice[..end]` there's [`slice_up_to`]. /// /// # Example /// /// ```rust /// use konst::slice::slice_range; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: &[u16] = slice_range(FIBB, 2, 4); /// const FOUR: &[u16] = slice_range(FIBB, 4, 7); /// const NONE: &[u16] = slice_range(FIBB, 0, 0); /// const ALL: &[u16] = slice_range(FIBB, 0, 1000); /// /// assert_eq!(TWO, &[8, 13]); /// assert_eq!(FOUR, &[21, 34, 55]); /// assert_eq!(NONE, &[]); /// assert_eq!(ALL, FIBB); /// /// ``` pub use konst_kernel::slice::slice_range; /// A const equivalent of `slice.get(start..)`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: Option<&[u16]> = slice::get_from(FIBB, 2); /// const FOUR: Option<&[u16]> = slice::get_from(FIBB, 4); /// const ALL: Option<&[u16]> = slice::get_from(FIBB, 0); /// const NONE: Option<&[u16]> = slice::get_from(FIBB, 1000); /// /// assert_eq!(TWO, Some(&[8, 13, 21, 34, 55, 89][..])); /// assert_eq!(FOUR, Some(&[21, 34, 55, 89][..])); /// assert_eq!(ALL, Some(FIBB)); /// assert_eq!(NONE, None); /// /// ``` #[inline] pub const fn get_from(slice: &[T], start: usize) -> Option<&[T]> { Some(__slice_from_impl!( slice, start, as_ptr, from_raw_parts, None )) } /// A const equivalent of `&mut slice[start..]`. /// /// If `slice.len() < start`, this simply returns an empty slice. /// /// # Example /// /// ```rust /// use konst::slice::slice_from_mut; /// /// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89]; /// /// assert_eq!(slice_from_mut(&mut fibs, 0), &mut [3, 5, 8, 13, 21, 34, 55, 89]); /// assert_eq!(slice_from_mut(&mut fibs, 1), &mut [5, 8, 13, 21, 34, 55, 89]); /// assert_eq!(slice_from_mut(&mut fibs, 2), &mut [8, 13, 21, 34, 55, 89]); /// assert_eq!(slice_from_mut(&mut fibs, 6), &mut [55, 89]); /// assert_eq!(slice_from_mut(&mut fibs, 7), &mut [89]); /// assert_eq!(slice_from_mut(&mut fibs, 8), &mut []); /// assert_eq!(slice_from_mut(&mut fibs, 1000), &mut []); /// /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn slice_from_mut(slice: &mut [T], start: usize) -> &mut [T] { __slice_from_impl!(slice, start, as_mut_ptr, from_raw_parts_mut, &mut []) } /// A const equivalent of `slice.get_mut(start..)`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// let mut fibs = [3, 5, 8, 13, 21, 34, 55]; /// /// assert_eq!(slice::get_from_mut(&mut fibs, 0), Some(&mut [3, 5, 8, 13, 21, 34, 55][..])); /// assert_eq!(slice::get_from_mut(&mut fibs, 1), Some(&mut [5, 8, 13, 21, 34, 55][..])); /// assert_eq!(slice::get_from_mut(&mut fibs, 2), Some(&mut [8, 13, 21, 34, 55][..])); /// assert_eq!(slice::get_from_mut(&mut fibs, 6), Some(&mut [55][..])); /// assert_eq!(slice::get_from_mut(&mut fibs, 7), Some(&mut [][..])); /// assert_eq!(slice::get_from_mut(&mut fibs, 8), None); /// assert_eq!(slice::get_from_mut(&mut fibs, 100), None); /// /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn get_from_mut(slice: &mut [T], start: usize) -> Option<&mut [T]> { Some(__slice_from_impl!( slice, start, as_mut_ptr, from_raw_parts_mut, None )) } /// A const equivalent of `slice.get(..len)`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: Option<&[u16]> = slice::get_up_to(FIBB, 2); /// const FOUR: Option<&[u16]> = slice::get_up_to(FIBB, 4); /// const NONE: Option<&[u16]> = slice::get_up_to(FIBB, 0); /// const ALL: Option<&[u16]> = slice::get_up_to(FIBB, 1000); /// /// assert_eq!(TWO, Some(&[3, 5][..])); /// assert_eq!(FOUR, Some(&[3, 5, 8, 13][..])); /// assert_eq!(NONE, Some(&[][..])); /// assert_eq!(ALL, None); /// /// ``` #[inline] pub const fn get_up_to(slice: &[T], len: usize) -> Option<&[T]> { Some(__slice_up_to_impl!( slice, len, as_ptr, from_raw_parts, None )) } /// A const equivalent of `&mut slice[..len]`. /// /// If `slice.len() < len`, this simply returns `slice` back. /// /// # Example /// /// ```rust /// use konst::slice::slice_up_to_mut; /// /// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89]; /// /// assert_eq!(slice_up_to_mut(&mut fibs, 100), &mut [3, 5, 8, 13, 21, 34, 55, 89]); /// assert_eq!(slice_up_to_mut(&mut fibs, 8), &mut [3, 5, 8, 13, 21, 34, 55, 89]); /// assert_eq!(slice_up_to_mut(&mut fibs, 7), &mut [3, 5, 8, 13, 21, 34, 55]); /// assert_eq!(slice_up_to_mut(&mut fibs, 6), &mut [3, 5, 8, 13, 21, 34]); /// assert_eq!(slice_up_to_mut(&mut fibs, 3), &mut [3, 5, 8]); /// assert_eq!(slice_up_to_mut(&mut fibs, 2), &mut [3, 5]); /// assert_eq!(slice_up_to_mut(&mut fibs, 1), &mut [3]); /// assert_eq!(slice_up_to_mut(&mut fibs, 0), &mut []); /// /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn slice_up_to_mut(slice: &mut [T], len: usize) -> &mut [T] { __slice_up_to_impl!(slice, len, as_mut_ptr, from_raw_parts_mut, slice) } /// A const equivalent of `slice.get_mut(..len)`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89]; /// /// assert_eq!(slice::get_up_to_mut(&mut fibs, 100), None); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 9), None); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 8), Some(&mut [3, 5, 8, 13, 21, 34, 55, 89][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 7), Some(&mut [3, 5, 8, 13, 21, 34, 55][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 6), Some(&mut [3, 5, 8, 13, 21, 34][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 3), Some(&mut [3, 5, 8][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 2), Some(&mut [3, 5][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 1), Some(&mut [3][..])); /// assert_eq!(slice::get_up_to_mut(&mut fibs, 0), Some(&mut [][..])); /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn get_up_to_mut(slice: &mut [T], len: usize) -> Option<&mut [T]> { Some(__slice_up_to_impl!( slice, len, as_mut_ptr, from_raw_parts_mut, None )) } /// A const equivalent of `slice.get(start..end)`. /// /// # Alternatives /// /// For a const equivalent of `slice.get(start..)` there's [`get_from`]. /// /// For a const equivalent of `slice.get(..end)` there's [`get_up_to`]. /// /// [`get_from`]: ./fn.get_from.html /// [`get_up_to`]: ./fn.get_up_to.html /// /// # Example /// /// ```rust /// use konst::slice; /// /// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89]; /// /// const TWO: Option<&[u16]> = slice::get_range(FIBB, 2, 4); /// const FOUR: Option<&[u16]> = slice::get_range(FIBB, 4, 7); /// const ALL: Option<&[u16]> = slice::get_range(FIBB, 0, 8); /// const EMPTY: Option<&[u16]> = slice::get_range(FIBB, 0, 0); /// const NONE: Option<&[u16]> = slice::get_range(FIBB, 0, 1000); /// /// assert_eq!(TWO, Some(&[8, 13][..])); /// assert_eq!(FOUR, Some(&[21, 34, 55][..])); /// assert_eq!(ALL, Some(FIBB)); /// assert_eq!(EMPTY, Some(&[][..])); /// assert_eq!(NONE, None); /// /// ``` pub const fn get_range(slice: &[T], start: usize, end: usize) -> Option<&[T]> { let x = crate::try_opt!(get_up_to(slice, end)); get_from(x, start) } /// A const equivalent of `&mut slice[start..end]`. /// /// If `start >= end ` or `slice.len() < start `, this returns an empty slice. /// /// If `slice.len() < end`, this returns the slice from `start`. /// /// /// # Alternatives /// /// For a const equivalent of `&mut slice[start..]` there's [`slice_from_mut`]. /// /// For a const equivalent of `&mut slice[..end]` there's [`slice_up_to_mut`]. /// /// [`slice_from_mut`]: ./fn.slice_from_mut.html /// [`slice_up_to_mut`]: ./fn.slice_up_to_mut.html /// /// # Example /// /// ```rust /// use konst::slice::slice_range_mut; /// /// let mut fibb = [3, 5, 8, 13, 21, 34, 55, 89]; /// /// assert_eq!(slice_range_mut(&mut fibb, 2, 4), &mut [8, 13]); /// assert_eq!(slice_range_mut(&mut fibb, 4, 7), &mut [21, 34, 55]); /// assert_eq!(slice_range_mut(&mut fibb, 0, 0), &mut []); /// assert_eq!(slice_range_mut(&mut fibb, 0, 1000), &mut [3, 5, 8, 13, 21, 34, 55, 89]); /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn slice_range_mut(slice: &mut [T], start: usize, end: usize) -> &mut [T] { slice_from_mut(slice_up_to_mut(slice, end), start) } /// A const equivalent of `slice.get_mut(start..end)`. /// /// /// # Alternatives /// /// For a const equivalent of `slice.get_mut(start..)` there's [`get_from_mut`]. /// /// For a const equivalent of `slice.get_mut(..end)` there's [`get_up_to_mut`]. /// /// [`get_from_mut`]: ./fn.get_from_mut.html /// [`get_up_to_mut`]: ./fn.get_up_to_mut.html /// /// # Example /// /// ```rust /// use konst::slice; /// /// let mut fibb = [3, 5, 8, 13, 21, 34, 55]; /// /// assert_eq!(slice::get_range_mut(&mut fibb, 0, 0), Some(&mut [][..])); /// assert_eq!(slice::get_range_mut(&mut fibb, 2, 4), Some(&mut [8, 13][..])); /// assert_eq!(slice::get_range_mut(&mut fibb, 4, 7), Some(&mut [21, 34, 55][..])); /// assert_eq!(slice::get_range_mut(&mut fibb, 0, 7), Some(&mut [3, 5, 8, 13, 21, 34, 55][..])); /// assert_eq!(slice::get_range_mut(&mut fibb, 0, 1000), None); /// /// ``` #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn get_range_mut(slice: &mut [T], start: usize, end: usize) -> Option<&mut [T]> { let x = crate::try_opt!(get_up_to_mut(slice, end)); get_from_mut(x, start) } /// A const equivalent of /// [`<[T]>::split_at`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at) /// /// If `at > slice.len()`, this returns a `slice`, empty slice pair. /// /// # Const stabilization /// /// The analogous std function was const-stabilized in Rust 1.71.0. /// /// # Example /// /// ```rust /// use konst::slice::split_at; /// /// let arr = [3, 5, 8, 13, 21, 34]; /// /// assert_eq!(split_at(&arr, 0), (&[][..], &[3, 5, 8, 13, 21, 34][..])); /// /// assert_eq!(split_at(&arr, 1), (&[3][..], &[5, 8, 13, 21, 34][..])); /// /// assert_eq!(split_at(&arr, 2), (&[3, 5][..], &[8, 13, 21, 34][..])); /// /// assert_eq!(split_at(&arr, 5), (&[3, 5, 8, 13, 21][..], &[34][..])); /// /// assert_eq!(split_at(&arr, 6), (&[3, 5, 8, 13, 21, 34][..], &[][..])); /// /// assert_eq!(split_at(&arr, 7), (&[3, 5, 8, 13, 21, 34][..], &[][..])); /// /// ``` /// pub const fn split_at(slice: &[T], at: usize) -> (&[T], &[T]) { (slice_up_to(slice, at), slice_from(slice, at)) } /// A const equivalent of /// [`<[T]>::split_at_mut` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut) /// /// If `at > slice.len()`, this returns a `slice`, empty slice pair. /// /// # Const stabilization /// /// The analogous std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::slice::split_at_mut; /// /// let mut arr = [3, 5, 8, 13, 21, 34]; /// /// assert_eq!(split_at_mut(&mut arr, 0), (&mut [][..], &mut [3, 5, 8, 13, 21, 34][..])); /// /// assert_eq!(split_at_mut(&mut arr, 1), (&mut [3][..], &mut [5, 8, 13, 21, 34][..])); /// /// assert_eq!(split_at_mut(&mut arr, 2), (&mut [3, 5][..], &mut [8, 13, 21, 34][..])); /// /// assert_eq!(split_at_mut(&mut arr, 5), (&mut [3, 5, 8, 13, 21][..], &mut [34][..])); /// /// assert_eq!(split_at_mut(&mut arr, 6), (&mut [3, 5, 8, 13, 21, 34][..], &mut [][..])); /// /// assert_eq!(split_at_mut(&mut arr, 7), (&mut [3, 5, 8, 13, 21, 34][..], &mut [][..])); /// /// ``` /// #[inline] #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn split_at_mut(slice: &mut [T], at: usize) -> (&mut [T], &mut [T]) { use core::slice::from_raw_parts_mut; if at > slice.len() { return (slice, &mut []); } let suffix_len = slice.len() - at; unsafe { let ptr = slice.as_mut_ptr(); let prefix = from_raw_parts_mut(ptr.offset(0), at); let suffix = from_raw_parts_mut(ptr.offset(at as isize), suffix_len); (prefix, suffix) } } /// Whether `pattern` is the start of `left`. /// /// This is analogous to /// [`<[u8]>::starts_with`](https://doc.rust-lang.org/std/primitive.slice.html#method.starts_with) /// /// # Example /// /// ```rust /// use konst::slice::bytes_start_with; /// /// assert!( bytes_start_with(b"foo,bar,baz", "foo,")); /// assert!( bytes_start_with(b"foo,bar,baz", &'f')); /// assert!( bytes_start_with(b"foo,bar,baz", &[b'f', b'o', b'o'])); /// assert!(!bytes_start_with(b"foo,bar,baz", "bar")); /// assert!(!bytes_start_with(b"foo,bar,baz", "baz")); /// /// ``` /// #[inline] pub const fn bytes_start_with(left: &[u8], pattern: &P) -> bool where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_start_with(left, pattern.as_bytes()) } #[inline(always)] pub(crate) const fn __bytes_start_with(left: &[u8], pattern: &[u8]) -> bool { matches!(__bytes_strip_prefix(left, pattern), Some(_)) } /// Remove `prefix` from the start of `left`. /// /// Returns `None` if `prefix` is not the start of `left`. /// /// This is analogous to /// [`<[u8]>::strip_prefix`](https://doc.rust-lang.org/std/primitive.slice.html#method.strip_prefix) /// /// # Example /// /// ```rust /// use konst::slice::bytes_strip_prefix; /// /// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"foo,"), Some("bar,baz".as_bytes())); /// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", "foo,bar,"), Some("baz".as_bytes())); /// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", &'f'), Some("oo,bar,baz".as_bytes())); /// /// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"bar"), None); /// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"baz"), None); /// /// ``` /// /// [`strip_prefix`]: /// https://doc.rust-lang.org/std/primitive.slice.html#method.strip_prefix /// #[inline] pub const fn bytes_strip_prefix<'a, const N: usize, P>( left: &'a [u8], prefix: &P, ) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let prefix = PatternNorm::new(prefix); __bytes_strip_prefix(left, prefix.as_bytes()) } pub(crate) const fn __bytes_strip_prefix<'a>( mut left: &'a [u8], mut prefix: &[u8], ) -> Option<&'a [u8]> { impl_bytes_function! { strip_prefix; left = left; right = prefix; on_error = return None, } Some(left) } /// Whether `pattern` is the end of `left`. /// /// A const analog of /// [`<[u8]>::ends_with`](https://doc.rust-lang.org/std/primitive.slice.html#method.ends_with) /// /// # Example /// /// ```rust /// use konst::slice::bytes_end_with; /// /// assert!( bytes_end_with(b"foo,bar,baz", b",baz")); /// assert!( bytes_end_with(b"foo,bar,baz", "bar,baz")); /// assert!( bytes_end_with(b"foo,bar,baz", &'z')); /// /// assert!(!bytes_end_with(b"foo,bar,baz", b"bar")); /// assert!(!bytes_end_with(b"foo,bar,baz", b"foo")); /// /// ``` /// #[inline] pub const fn bytes_end_with(left: &[u8], pattern: &P) -> bool where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_end_with(left, pattern.as_bytes()) } pub(crate) const fn __bytes_end_with(left: &[u8], pattern: &[u8]) -> bool { matches!(__bytes_strip_suffix(left, pattern), Some(_)) } /// Remove `suffix` from the end of `left`. /// /// Returns `None` if `suffix` is not the end of `left`. /// /// A const analog of /// [`<[u8]>::strip_suffix`](https://doc.rust-lang.org/std/primitive.slice.html#method.strip_suffix) /// /// # Example /// /// ```rust /// use konst::slice::bytes_strip_suffix; /// /// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", b",baz"), Some("foo,bar".as_bytes())); /// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", ",bar,baz"), Some("foo".as_bytes())); /// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", &'z'), Some("foo,bar,ba".as_bytes())); /// /// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", b"bar"), None); /// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", "foo"), None); /// /// ``` /// /// [`strip_suffix`]: /// https://doc.rust-lang.org/std/primitive.slice.html#method.strip_suffix /// #[inline] pub const fn bytes_strip_suffix<'a, const N: usize, P>( left: &'a [u8], suffix: &P, ) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let suffix = PatternNorm::new(suffix); __bytes_strip_suffix(left, suffix.as_bytes()) } pub(crate) const fn __bytes_strip_suffix<'a>( mut left: &'a [u8], mut suffix: &[u8], ) -> Option<&'a [u8]> { impl_bytes_function! { strip_suffix; left = left; right = suffix; on_error = return None, } Some(left) } /// Finds the byte offset of `pattern` in `left`. /// /// Returns `None` if `pattern` isn't inside `left` /// /// # Example /// /// ```rust /// use konst::slice::bytes_find; /// /// assert_eq!(bytes_find(b"foo-bar-baz", &'q'), None); /// assert_eq!(bytes_find(b"foo-bar-baz", "foo"), Some(0)); /// assert_eq!(bytes_find(b"foo-bar-baz", b"bar"), Some(4)); /// assert_eq!(bytes_find(b"foo-bar-baz", b"baz"), Some(8)); /// /// ``` /// #[inline] pub const fn bytes_find(left: &[u8], pattern: &P) -> Option where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_find(left, pattern.as_bytes()) } pub(crate) const fn __bytes_find(left: &[u8], pattern: &[u8]) -> Option { let mut matching = pattern; crate::for_range! {i in 0..left.len() => match matching { [mb, m_rem @ ..] => { let b = left[i]; matching = if b == *mb { m_rem } else { match pattern { // For when the string is "lawlawn" and we are trying to find "lawn" [mb2, m_rem2 @ ..] if b == *mb2 => m_rem2, _ => pattern, } }; } [] => { return Some(i - pattern.len()) } } } if matching.is_empty() { Some(left.len() - pattern.len()) } else { None } } /// Whether `pattern` is inside `left`. /// /// # Example /// /// ```rust /// use konst::slice::bytes_contain; /// /// assert!(bytes_contain(b"foo-bar", b"foo")); /// assert!(bytes_contain(b"bar-foo", "foo")); /// /// assert!(!bytes_contain(b"foo-bar-baz", &'q')); /// /// ``` /// #[inline] pub const fn bytes_contain(left: &[u8], pattern: &P) -> bool where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_contain(left, pattern.as_bytes()) } #[inline(always)] const fn __bytes_contain(left: &[u8], pattern: &[u8]) -> bool { matches!(__bytes_find(left, pattern), Some(_)) } /// Finds the byte offset of `pattern` inside `left`, searching in reverse. /// /// Returns `None` if `pattern` isn't inside `left`. /// /// # Example /// /// ```rust /// use konst::slice::bytes_rfind; /// /// assert_eq!(bytes_rfind(b"foo-bar-baz", &'q'), None); /// assert_eq!(bytes_rfind(b"foo-bar-baz", b"foo"), Some(0)); /// assert_eq!(bytes_rfind(b"foo-bar-baz", "bar"), Some(4)); /// assert_eq!(bytes_rfind(b"foo-bar-baz", b"baz"), Some(8)); /// /// ``` /// #[inline] pub const fn bytes_rfind(left: &[u8], pattern: &P) -> Option where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_rfind(left, pattern.as_bytes()) } pub(crate) const fn __bytes_rfind(left: &[u8], pattern: &[u8]) -> Option { let mut matching = pattern; let llen = left.len(); let mut i = llen; while i != 0 { i -= 1; match matching { [m_rem @ .., mb] => { let b = left[i]; matching = if b == *mb { m_rem } else { match pattern { // For when the string is "lawlawn" and we are trying to find "lawn" [m_rem2 @ .., mb2] if b == *mb2 => m_rem2, _ => pattern, } }; } [] => return Some(i + (!pattern.is_empty()) as usize), } } if matching.is_empty() { Some(i) } else { None } } /// Returns whether `pattern` is contained inside `left`, searching in reverse. /// /// # Example /// /// ```rust /// use konst::slice::bytes_rcontain; /// /// assert!(bytes_rcontain(b"foo-bar", b"foo")); /// assert!(bytes_rcontain(b"bar-foo", "foo")); /// /// assert!(!bytes_rcontain(b"foo-bar-baz", &'q')); /// /// ``` /// #[inline] pub const fn bytes_rcontain(left: &[u8], pattern: &P) -> bool where P: ?Sized + BytesPattern, { let pattern = PatternNorm::new(pattern); __bytes_rcontain(left, pattern.as_bytes()) } #[inline(always)] pub(crate) const fn __bytes_rcontain(left: &[u8], pattern: &[u8]) -> bool { matches!(bytes_rfind(left, pattern), Some(_)) } macro_rules! matches_space { ($b:ident) => { matches!($b, b'\t' | b'\n' | b'\r' | b' ') }; } /// Removes ascii whitespace from the start and end of `this`. /// /// # Const stabilization /// /// The [equivalent std function]( /// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii) /// was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED: &[u8] = slice::bytes_trim(b"\nhello world "); /// /// assert_eq!(TRIMMED, b"hello world"); /// /// ``` pub const fn bytes_trim(this: &[u8]) -> &[u8] { bytes_trim_start(bytes_trim_end(this)) } /// Removes ascii whitespace from the start of `this`. /// /// # Const stabilization /// /// The [equivalent std function]( /// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii_start) /// was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED: &[u8] = slice::bytes_trim_start(b"\tfoo bar "); /// /// assert_eq!(TRIMMED, b"foo bar "); /// /// ``` pub const fn bytes_trim_start(mut this: &[u8]) -> &[u8] { loop { match this { [b, rem @ ..] if matches_space!(b) => this = rem, _ => return this, } } } /// Removes ascii whitespace from the end of `this`. /// /// # Const stabilization /// /// The [equivalent std function]( /// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii_end) /// was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED: &[u8] = slice::bytes_trim_end(b"\rfoo bar "); /// /// assert_eq!(TRIMMED, b"\rfoo bar"); /// /// ``` pub const fn bytes_trim_end(mut this: &[u8]) -> &[u8] { loop { match this { [rem @ .., b] if matches_space!(b) => this = rem, _ => return this, } } } /// Removes all instances of `needle` from the start and end of `this`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED0: &[u8] = slice::bytes_trim_matches(b"<>baz qux<><><>", b"<>"); /// assert_eq!(TRIMMED0, b"baz qux"); /// /// const TRIMMED1: &[u8] = slice::bytes_trim_matches(b"{}foo bar{}{}", "{}"); /// assert_eq!(TRIMMED1, b"foo bar"); /// /// const TRIMMED2: &[u8] = slice::bytes_trim_matches(b"-----soming----", &'-'); /// assert_eq!(TRIMMED2, b"soming"); /// /// /// ``` pub const fn bytes_trim_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8] where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_trim_matches(this, needle.as_bytes()) } pub(crate) const fn __bytes_trim_matches<'a>(this: &'a [u8], needle: &[u8]) -> &'a [u8] { let ltrim = __bytes_trim_start_matches(this, needle); __bytes_trim_end_matches(ltrim, needle) } /// Removes all instances of `needle` from the start of `this`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED0: &[u8] = slice::bytes_trim_start_matches(b"#####huh###", b"##"); /// const TRIMMED1: &[u8] = slice::bytes_trim_start_matches(b"[][]nice[][]", "[][]"); /// const TRIMMED2: &[u8] = slice::bytes_trim_start_matches(b"(((woah", &'('); /// /// assert_eq!(TRIMMED0, b"#huh###"); /// assert_eq!(TRIMMED1, b"nice[][]"); /// assert_eq!(TRIMMED2, b"woah"); /// /// ``` pub const fn bytes_trim_start_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8] where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_trim_start_matches(this, needle.as_bytes()) } pub(crate) const fn __bytes_trim_start_matches<'a>(mut this: &'a [u8], needle: &[u8]) -> &'a [u8] { if needle.is_empty() { return this; } let mut matched = needle; loop { let at_start = this; match (this, matched) { ([b, rem @ ..], [bm, remm @ ..]) if *b == *bm => { this = rem; matched = remm; } _ => return this, } 'inner: loop { match (this, matched) { ([], [_, ..]) => return at_start, ([b, rem @ ..], [bm, remm @ ..]) => { if *b == *bm { this = rem; matched = remm; } else { return at_start; } } _ => break 'inner, } } matched = needle; } } /// Removes all instances of `needle` from the end of `this`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// const TRIMMED0: &[u8] = slice::bytes_trim_end_matches(b"oowowooooo", b"oo"); /// const TRIMMED1: &[u8] = slice::bytes_trim_end_matches(b"gooooo", "oo"); /// const TRIMMED2: &[u8] = slice::bytes_trim_end_matches(b"yesssssss", &'s'); /// /// assert_eq!(TRIMMED0, b"oowowo"); /// assert_eq!(TRIMMED1, b"go"); /// assert_eq!(TRIMMED2, b"ye"); /// /// ``` pub const fn bytes_trim_end_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8] where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_trim_end_matches(this, needle.as_bytes()) } pub(crate) const fn __bytes_trim_end_matches<'a>(mut this: &'a [u8], needle: &[u8]) -> &'a [u8] { if needle.is_empty() { return this; } let mut matched = needle; loop { let at_start = this; match (this, matched) { ([rem @ .., b], [remm @ .., bm]) if *b == *bm => { this = rem; matched = remm; } _ => return this, } 'inner: loop { match (this, matched) { ([], [.., _]) => return at_start, ([rem @ .., b], [remm @ .., bm]) => { if *b == *bm { this = rem; matched = remm; } else { return at_start; } } _ => break 'inner, } } matched = needle; } } macro_rules! elem_then_rem { ($elem:ident, $($rem:tt)*) => { [$elem, $($rem)*] }; } macro_rules! rem_then_elem { ($elem:ident, $($rem:tt)*) => { [$($rem)*, $elem] }; } macro_rules! byte_find_then { ($slice_order:ident, $this:ident, $needle:ident, |$next:ident| $then:block) => ({ if $needle.is_empty() { return Some($this); } let mut matching = $needle; let mut $next = $this; while let $slice_order!(mb, ref m_rem @ ..) = *matching { matching = m_rem; if let $slice_order!(b, ref rem @ ..) = *$next { if b != mb { matching = match *$needle { // For when the string is "lawlawn" and we are skipping "lawn" $slice_order!(mb2, ref m_rem2 @ ..) if b == mb2 => { // This is considered used in half of the macro invocations #[allow(unused_assignments)] {$this = $next;} m_rem2 }, _ => { // This is considered used in half of the macro invocations #[allow(unused_assignments)] {$this = rem;} $needle }, }; } $next = rem; } else { return None; } } $then Some($this) }); } /// Advances `this` past the first instance of `needle`. /// /// Return `None` if no instance of `needle` is found. /// /// Return `Some(this)` if `needle` is empty. /// /// # Example /// /// ```rust /// use konst::slice::bytes_find_skip; /// /// { /// const FOUND: Option<&[u8]> = bytes_find_skip(b"foo bar baz", b"bar"); /// assert_eq!(FOUND, Some(&b" baz"[..])); /// } /// { /// const NOT_FOUND: Option<&[u8]> = bytes_find_skip(b"foo bar baz", &'q'); /// assert_eq!(NOT_FOUND, None); /// } /// { /// const EMPTY_NEEDLE: Option<&[u8]> = bytes_find_skip(b"foo bar baz", ""); /// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..])); /// } /// ``` pub const fn bytes_find_skip<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_find_skip(this, needle.as_bytes()) } pub(crate) const fn __bytes_find_skip<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> { byte_find_then! {elem_then_rem, this, needle, |next| {this = next}} } /// Advances `this` up to the first instance of `needle`. /// /// Return `None` if no instance of `needle` is found. /// /// Return `Some(this)` if `needle` is empty. /// /// # Example /// /// ```rust /// use konst::slice::bytes_find_keep; /// /// { /// const FOUND: Option<&[u8]> = bytes_find_keep(b"foo bar baz", b"bar"); /// assert_eq!(FOUND, Some(&b"bar baz"[..])); /// } /// { /// const NOT_FOUND: Option<&[u8]> = bytes_find_keep(b"foo bar baz", &'q'); /// assert_eq!(NOT_FOUND, None); /// } /// { /// const EMPTY_NEEDLE: Option<&[u8]> = bytes_find_keep(b"foo bar baz", ""); /// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..])); /// } /// ``` pub const fn bytes_find_keep<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_find_keep(this, needle.as_bytes()) } pub(crate) const fn __bytes_find_keep<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> { byte_find_then! {elem_then_rem, this, needle, |next| {}} } /// Truncates `this` to before the last instance of `needle`. /// /// Return `None` if no instance of `needle` is found. /// /// Return `Some(this)` if `needle` is empty. /// /// # Example /// /// ```rust /// use konst::slice::bytes_rfind_skip; /// /// { /// const FOUND: Option<&[u8]> = bytes_rfind_skip(b"foo bar _ bar baz", b"bar"); /// assert_eq!(FOUND, Some(&b"foo bar _ "[..])); /// } /// { /// const NOT_FOUND: Option<&[u8]> = bytes_rfind_skip(b"foo bar baz", &'q'); /// assert_eq!(NOT_FOUND, None); /// } /// { /// const EMPTY_NEEDLE: Option<&[u8]> = bytes_rfind_skip(b"foo bar baz", ""); /// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..])); /// } /// ``` pub const fn bytes_rfind_skip<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_rfind_skip(this, needle.as_bytes()) } pub(crate) const fn __bytes_rfind_skip<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> { byte_find_then! {rem_then_elem, this, needle, |next| {this = next}} } /// Truncates `this` to the last instance of `needle`. /// /// Return `None` if no instance of `needle` is found. /// /// Return `Some(this)` if `needle` is empty. /// /// # Example /// /// ```rust /// use konst::slice::bytes_rfind_keep; /// /// { /// const FOUND: Option<&[u8]> = bytes_rfind_keep(b"foo bar _ bar baz", b"bar"); /// assert_eq!(FOUND, Some(&b"foo bar _ bar"[..])); /// } /// { /// const NOT_FOUND: Option<&[u8]> = bytes_rfind_keep(b"foo bar baz", &'q'); /// assert_eq!(NOT_FOUND, None); /// } /// { /// const EMPTY_NEEDLE: Option<&[u8]> = bytes_rfind_keep(b"foo bar baz", ""); /// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..])); /// } /// ``` pub const fn bytes_rfind_keep<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]> where P: ?Sized + BytesPattern, { let needle = PatternNorm::new(needle); __bytes_rfind_keep(this, needle.as_bytes()) } pub(crate) const fn __bytes_rfind_keep<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> { byte_find_then! {rem_then_elem, this, needle, |next| {}} } /// A const equivalent of /// [`<[T]>::first_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) /// /// # Example /// /// ```rust /// use konst::slice; /// /// assert_eq!(slice::first_mut(&mut [8, 5, 3]), Some(&mut 8)); /// /// assert_eq!(slice::first_mut(&mut [5, 3]), Some(&mut 5)); /// /// assert_eq!(slice::first_mut(&mut [3]), Some(&mut 3)); /// /// assert_eq!(slice::first_mut::(&mut []), None); /// /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn first_mut(slice: &mut [T]) -> Option<&mut T> { if let [first, ..] = slice { Some(first) } else { None } } /// A const equivalent of /// [`<[T]>::last_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// assert_eq!(slice::last_mut(&mut [3, 5, 8]), Some(&mut 8)); /// /// assert_eq!(slice::last_mut(&mut [3, 5]), Some(&mut 5)); /// /// assert_eq!(slice::last_mut(&mut [3]), Some(&mut 3)); /// /// assert_eq!(slice::last_mut::(&mut []), None); /// /// ``` #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn last_mut(slice: &mut [T]) -> Option<&mut T> { if let [.., last] = slice { Some(last) } else { None } } /// A const equivalent of /// [`<[T]>::split_first_mut` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first_mut) /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// assert_eq!(slice::split_first_mut(&mut [5, 8, 13, 21]), Some((&mut 5, &mut [8, 13, 21][..]))); /// assert_eq!(slice::split_first_mut(&mut [8, 13, 21]), Some((&mut 8, &mut [13, 21][..]))); /// assert_eq!(slice::split_first_mut(&mut [13, 21]), Some((&mut 13, &mut [21][..]))); /// assert_eq!(slice::split_first_mut(&mut [21]), Some((&mut 21, &mut [][..]))); /// assert_eq!(slice::split_first_mut::<()>(&mut []), None); /// /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn split_first_mut(slice: &mut [T]) -> Option<(&mut T, &mut [T])> { if let [first, rem @ ..] = slice { Some((first, rem)) } else { None } } /// A const equivalent of /// [`<[T]>::split_last_mut` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_last_mut) /// /// # Const stabilization /// /// The equivalent std function was const-stabilized in Rust 1.83.0. /// /// # Example /// /// ```rust /// use konst::slice; /// /// assert_eq!(slice::split_last_mut(&mut [8, 13, 21, 5]), Some((&mut 5, &mut [8, 13, 21][..]))); /// assert_eq!(slice::split_last_mut(&mut [13, 21, 8]), Some((&mut 8, &mut [13, 21][..]))); /// assert_eq!(slice::split_last_mut(&mut [21, 13]), Some((&mut 13, &mut [21][..]))); /// assert_eq!(slice::split_last_mut(&mut [21]), Some((&mut 21, &mut [][..]))); /// assert_eq!(slice::split_last_mut::<()>(&mut []), None); /// /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] pub const fn split_last_mut(slice: &mut [T]) -> Option<(&mut T, &mut [T])> { if let [rem @ .., last] = slice { Some((last, rem)) } else { None } } konst-0.3.16/src/slice/slice_iter_methods.rs000064400000000000000000000622531046102023000171620ustar 00000000000000use crate::{ iter::{ConstIntoIter, IsIteratorKind}, option, slice, }; use konst_kernel::iterator_shared; /// Gets a const iterator over `slice`, const equivalent of /// [`<[T]>::iter` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.iter) /// /// # Example /// /// ### Normal /// /// ```rust /// use konst::iter::for_each; /// use konst::slice; /// /// const ARR: &[usize] = &{ /// let mut arr = [0usize; 3]; /// // the `slice::iter` call here is unnecessary, /// // you can pass a slice reference to `for_each` /// for_each!{(i, elem) in slice::iter(&["foo", "hello", "That box"]), enumerate() => /// arr[i] = elem.len(); /// } /// arr /// }; /// /// assert_eq!(ARR, [3, 5, 8]); /// /// ``` /// /// ### Reversed /// /// ```rust /// use konst::iter::for_each; /// use konst::slice; /// /// const ARR: &[usize] = &{ /// let mut arr = [0usize; 3]; /// for_each!{(i, elem) in slice::iter(&["foo", "hello", "That box"]).rev(),enumerate() => /// arr[i] = elem.len(); /// } /// arr /// }; /// /// assert_eq!(ARR, [8, 5, 3]); /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::iter; /// Const equivalent of [`core::slice::Iter`]. /// /// This is constructed in either of these ways: /// ```rust /// # let a_slice = &[3]; /// # let _ = ( /// konst::slice::iter(a_slice) /// # , /// konst::iter::into_iter!(a_slice) /// # ); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::Iter; /// Const equivalent of `core::iter::Rev>` /// /// This is constructed in either of these ways: /// ```rust /// # let a_slice = &[3]; /// # let _ = ( /// konst::slice::iter(a_slice).rev() /// # , /// konst::iter::into_iter!(a_slice).rev() /// # ); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::IterRev; /// A const equivalent of `slice.iter().copied()` /// /// # Example /// /// ```rust /// use konst::{iter, slice}; /// /// const fn find_even(slice: &[u32]) -> Option { /// iter::eval!(slice::iter_copied(slice),find(|elem| *elem % 2 == 0)) /// } /// /// assert_eq!(find_even(&[]), None); /// assert_eq!(find_even(&[1]), None); /// assert_eq!(find_even(&[1, 2]), Some(2)); /// assert_eq!(find_even(&[5, 4, 3, 2, 1]), Some(4)); /// /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::iter_copied; /// A const equivalent of `iter::Copied>`. /// /// This const iterator can be created with [`iter_copied`]. #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::IterCopied; /// A const equivalent of `iter::Rev>>` /// /// This const iterator can be created with /// ```rust /// # let slice = &[3, 5, 8]; /// # let _: konst::slice::IterCopiedRev<'_, u32> = /// konst::slice::iter_copied(slice).rev() /// # ; /// ``` /// /// # Example /// /// ```rust /// use konst::iter; /// use konst::slice::{self, IterCopiedRev}; /// /// const fn rfind_even(slice: &[u32]) -> Option { /// let iter: IterCopiedRev<'_, u32> = slice::iter_copied(slice).rev(); /// iter::eval!(iter,find(|&elem| elem % 2 == 0)) /// } /// /// assert_eq!(rfind_even(&[]), None); /// assert_eq!(rfind_even(&[1]), None); /// assert_eq!(rfind_even(&[1, 2]), Some(2)); /// assert_eq!(rfind_even(&[1, 2, 3, 4, 5]), Some(4)); /// /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::into_iter::slice_into_iter::IterCopiedRev; /////////////////////////////////////////////////////////////////////////////// mod requires_rust_1_64 { use super::*; #[inline(always)] pub(crate) const fn some_if_nonempty(slice: &[T]) -> Option<&[T]> { if let [] = slice { None } else { Some(slice) } } /// Const equivalent of /// [`<[T]>::windows` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.windows) /// /// # Panics /// /// Panics if `size == 0`. /// /// # Example /// /// ```rust /// use konst::{iter, slice}; /// /// const fn is_sorted(slice: &[u8]) -> bool { /// iter::eval!(slice::windows(slice, 2),all(|w| w[1] > w[0])) /// } /// /// assert!(is_sorted(&[3, 5, 8])); /// assert!(!is_sorted(&[8, 13, 0])); /// /// /// /// ``` #[track_caller] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn windows(slice: &[T], size: usize) -> Windows<'_, T> { assert!(size != 0, "window size must be non-zero"); Windows { slice, size } } macro_rules! windows_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T], iter_forward = Windows<'a, T>, iter_reversed = WindowsRev<'a, T>, next(self){ if self.slice.len() < self.size { None } else { let up_to = slice::slice_up_to(self.slice, self.size); self.slice = slice::slice_from(self.slice, 1); Some((up_to, self)) } }, next_back { let len = self.slice.len(); if len < self.size { None } else { let up_to = slice::slice_from(self.slice, len - self.size); self.slice = slice::slice_up_to(self.slice, len - 1); Some((up_to, self)) } }, fields = {slice, size}, } }; } /// Const equivalent of [`core::slice::Windows`] /// /// This is constructed with [`windows`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::windows(slice, 1) /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct Windows<'a, T> { slice: &'a [T], size: usize, } impl<'a, T> ConstIntoIter for Windows<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } /// Const equivalent of `core::iter::Rev` /// /// This is constructed with [`windows`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::windows(slice, 1).rev() /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct WindowsRev<'a, T> { slice: &'a [T], size: usize, } impl<'a, T> ConstIntoIter for WindowsRev<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } impl<'a, T> Windows<'a, T> { windows_shared! {is_forward = true} } impl<'a, T> WindowsRev<'a, T> { windows_shared! {is_forward = false} } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /// Const equivalent of /// [`<[T]>::array_chunks` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.array_chunks) /// /// # Panics /// /// Panics if `N == 0`. /// /// # Example /// /// ```rust /// use konst::slice; /// /// let arr = [3, 5, 8, 13, 21, 34, 55]; /// /// let iter = slice::array_chunks::<_, 2>(&arr); /// /// let (val0, iter) = iter.next().unwrap(); /// let (val1, iter) = iter.next().unwrap(); /// let (val2, iter) = iter.next().unwrap(); /// /// let out: [[u8; 2]; 3] = [*val0, *val1, *val2]; /// assert_eq!(out, [[3, 5], [8, 13], [21, 34]]); /// /// assert_eq!(iter.remainder(), &[55][..]); /// ``` pub const fn array_chunks<'a, T, const N: usize>(slice: &'a [T]) -> ArrayChunks<'a, T, N> { let (arrays, rem) = slice::as_chunks(slice); ArrayChunks { arrays, rem } } macro_rules! array_chunks_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T; N], iter_forward = ArrayChunks<'a, T, N>, iter_reversed = ArrayChunksRev<'a, T, N>, next(self) { match self.arrays { [elem, arrays @ ..] => Some((elem, Self {arrays, rem: self.rem})), [] => None, } }, next_back { match self.arrays { [arrays @ .., elem] => Some((elem, Self {arrays, rem: self.rem})), [] => None, } }, fields = {arrays, rem}, } }; } /// Const equivalent of [`core::slice::ArrayChunks`] pub struct ArrayChunks<'a, T, const N: usize> { arrays: &'a [[T; N]], rem: &'a [T], } impl<'a, T, const N: usize> ConstIntoIter for ArrayChunks<'a, T, N> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T; N]; } /// Const equivalent of `core::iter::Rev` pub struct ArrayChunksRev<'a, T, const N: usize> { arrays: &'a [[T; N]], rem: &'a [T], } impl<'a, T, const N: usize> ConstIntoIter for ArrayChunksRev<'a, T, N> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T; N]; } impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { array_chunks_shared! {is_forward = true} /// Accesses the trailing part of the slice that's not returned by the iterator, /// because it's shorter than `Ǹ` elements long. pub const fn remainder(&self) -> &'a [T] { self.rem } } impl<'a, T, const N: usize> ArrayChunksRev<'a, T, N> { array_chunks_shared! {is_forward = false} } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /// Const equivalent of /// [`<[T]>::chunks`](https://doc.rust-lang.org/std/primitive.slice.html#method.chunks) /// /// # Panics /// /// Panics if `chunk_size == 0`. /// /// # Example /// /// ```rust /// use konst::iter::collect_const; /// use konst::slice; /// /// const CHUNKS: [&[u8]; 3] = collect_const!{&[u8] => /// slice::chunks(&[3, 5, 8, 13, 21, 34, 55, 89], 3) /// }; /// /// let expected: &[&[u8]] = &[&[3, 5, 8], &[13, 21, 34], &[55, 89]]; /// /// assert_eq!(CHUNKS, expected) /// /// ``` /// #[track_caller] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn chunks(slice: &[T], chunk_size: usize) -> Chunks<'_, T> { assert!(chunk_size != 0, "chunk size must be non-zero"); Chunks { slice: some_if_nonempty(slice), chunk_size, } } macro_rules! chunks_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T], iter_forward = Chunks<'a, T>, iter_reversed = ChunksRev<'a, T>, next(self) { option::map!(self.slice, |slice| { let (ret, next) = slice::split_at(slice, self.chunk_size); self.slice = some_if_nonempty(next); (ret, self) }) }, next_back{ option::map!(self.slice, |slice| { let at = (slice.len() - 1) / self.chunk_size * self.chunk_size; let (next, ret) = slice::split_at(slice, at); self.slice = some_if_nonempty(next); (ret, self) }) }, fields = {slice, chunk_size}, } }; } /// Const equivalent of [`core::slice::Chunks`] /// /// This is constructed with [`chunks`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::chunks(slice, 1) /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct Chunks<'a, T> { slice: Option<&'a [T]>, chunk_size: usize, } impl<'a, T> ConstIntoIter for Chunks<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } /// Const equivalent of `core::iter::Rev` /// /// This is constructed with [`chunks`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::chunks(slice, 1).rev() /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct ChunksRev<'a, T> { slice: Option<&'a [T]>, chunk_size: usize, } impl<'a, T> ConstIntoIter for ChunksRev<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } impl<'a, T> Chunks<'a, T> { chunks_shared! {is_forward = true} } impl<'a, T> ChunksRev<'a, T> { chunks_shared! {is_forward = false} } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /// Const equivalent of /// [`<[T]>::rchunks`](https://doc.rust-lang.org/std/primitive.slice.html#method.rchunks) /// /// # Panics /// /// Panics if `chunk_size == 0`. /// /// # Example /// /// ```rust /// use konst::iter::collect_const; /// use konst::slice; /// /// const CHUNKS: [&[u8]; 3] = collect_const!{&[u8] => /// slice::rchunks(&[3, 5, 8, 13, 21, 34, 55, 89], 3) /// }; /// /// let expected: &[&[u8]] = &[&[34, 55, 89], &[8, 13, 21], &[3, 5]]; /// /// assert_eq!(CHUNKS, expected) /// /// ``` #[track_caller] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn rchunks(slice: &[T], chunk_size: usize) -> RChunks<'_, T> { assert!(chunk_size != 0, "chunk size must be non-zero"); RChunks { slice: some_if_nonempty(slice), chunk_size, } } macro_rules! rchunks_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T], iter_forward = RChunks<'a, T>, iter_reversed = RChunksRev<'a, T>, next(self) { option::map!(self.slice, |slice| { let at = slice.len().saturating_sub(self.chunk_size); let (next, ret) = slice::split_at(slice, at); self.slice = some_if_nonempty(next); (ret, self) }) }, next_back{ option::map!(self.slice, |slice| { let rem = slice.len() % self.chunk_size; let at = if rem == 0 { self.chunk_size } else { rem }; let (ret, next) = slice::split_at(slice, at); self.slice = some_if_nonempty(next); (ret, self) }) }, fields = {slice, chunk_size}, } }; } /// Const equivalent of [`core::slice::RChunks`] /// /// This is constructed with [`rchunks`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::rchunks(slice, 1) /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RChunks<'a, T> { slice: Option<&'a [T]>, chunk_size: usize, } impl<'a, T> ConstIntoIter for RChunks<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } /// Const equivalent of `core::iter::Rev` /// /// This is constructed with [`rchunks`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::rchunks(slice, 1).rev() /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RChunksRev<'a, T> { slice: Option<&'a [T]>, chunk_size: usize, } impl<'a, T> ConstIntoIter for RChunksRev<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } impl<'a, T> RChunks<'a, T> { rchunks_shared! {is_forward = true} } impl<'a, T> RChunksRev<'a, T> { rchunks_shared! {is_forward = false} } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /// Const equivalent of /// [`<[T]>::chunks_exact` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.chunks_exact) /// /// # Panics /// /// Panics if `chunk_size == 0`. /// /// # Example /// /// ```rust /// use konst::{option, slice}; /// /// const FOUND: [&[u8]; 3] = { /// let iter = slice::chunks_exact(&[3, 5, 8, 13, 21, 34, 55, 89], 3); /// let (elem0, iter) = option::unwrap!(iter.next()); /// let (elem1, iter) = option::unwrap!(iter.next()); /// [elem0, elem1, iter.remainder()] /// }; /// /// let expected: [&[u8]; 3] = [&[3u8, 5, 8], &[13, 21, 34], &[55, 89]]; /// /// assert_eq!(FOUND, expected); /// /// ``` /// #[track_caller] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn chunks_exact(slice: &[T], chunk_size: usize) -> ChunksExact<'_, T> { assert!(chunk_size != 0, "chunk size must be non-zero"); let at = slice.len() - slice.len() % chunk_size; let (slice, rem) = slice::split_at(slice, at); ChunksExact { slice, rem, chunk_size, } } macro_rules! chunks_exact_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T], iter_forward = ChunksExact<'a, T>, iter_reversed = ChunksExactRev<'a, T>, next(self) { if self.slice.is_empty() { None } else { let (ret, next) = slice::split_at(self.slice, self.chunk_size); self.slice = next; Some((ret, self)) } }, next_back { if self.slice.is_empty() { None } else { let at = self.slice.len() - self.chunk_size; let (next, ret) = slice::split_at(self.slice, at); self.slice = next; Some((ret, self)) } }, fields = {slice, rem, chunk_size}, } /// Returns the remainder of the slice that's not returned by [`next`](Self::next), /// because it is shorter than the chunk size. pub const fn remainder(&self) -> &'a [T] { self.rem } }; } /// Const equivalent of [`core::slice::ChunksExact`] /// /// This is constructed with [`chunks_exact`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::chunks_exact(slice, 1) /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct ChunksExact<'a, T> { slice: &'a [T], rem: &'a [T], chunk_size: usize, } impl<'a, T> ConstIntoIter for ChunksExact<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } /// Const equivalent of `core::iter::Rev` /// /// This is constructed with [`chunks_exact`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::chunks_exact(slice, 1).rev() /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct ChunksExactRev<'a, T> { slice: &'a [T], rem: &'a [T], chunk_size: usize, } impl<'a, T> ConstIntoIter for ChunksExactRev<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } impl<'a, T> ChunksExact<'a, T> { chunks_exact_shared! {is_forward = true} } impl<'a, T> ChunksExactRev<'a, T> { chunks_exact_shared! {is_forward = false} } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /// Const equivalent of /// [`<[T]>::rchunks_exact` /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.rchunks_exact) /// /// # Panics /// /// Panics if `chunk_size == 0`. /// /// # Example /// /// ```rust /// use konst::{option, slice}; /// /// const FOUND: [&[u8]; 3] = { /// let iter = slice::rchunks_exact(&[3, 5, 8, 13, 21, 34, 55, 89], 3); /// let (elem0, iter) = option::unwrap!(iter.next()); /// let (elem1, iter) = option::unwrap!(iter.next()); /// [elem0, elem1, iter.remainder()] /// }; /// /// let expected: [&[u8]; 3] = [&[34, 55, 89], &[8, 13, 21], &[3, 5]]; /// /// assert_eq!(FOUND, expected); /// /// ``` /// #[track_caller] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn rchunks_exact(slice: &[T], chunk_size: usize) -> RChunksExact<'_, T> { assert!(chunk_size != 0, "chunk size must be non-zero"); let (rem, slice) = slice::split_at(slice, slice.len() % chunk_size); RChunksExact { slice, rem, chunk_size, } } macro_rules! rchunks_exact_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = &'a [T], iter_forward = RChunksExact<'a, T>, iter_reversed = RChunksExactRev<'a, T>, next(self) { if self.slice.is_empty() { None } else { let at = self.slice.len() - self.chunk_size; let (next, ret) = slice::split_at(self.slice, at); self.slice = next; Some((ret, self)) } }, next_back { if self.slice.is_empty() { None } else { let (ret, next) = slice::split_at(self.slice, self.chunk_size); self.slice = next; Some((ret, self)) } }, fields = {slice, rem, chunk_size}, } /// Returns the remainder of the slice that's not returned by [`next`](Self::next), /// because it is shorter than the chunk size. pub const fn remainder(&self) -> &'a [T] { self.rem } }; } /// Const equivalent of [`core::slice::RChunksExact`] /// /// This is constructed with [`rchunks_exact`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::rchunks_exact(slice, 1) /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RChunksExact<'a, T> { slice: &'a [T], rem: &'a [T], chunk_size: usize, } impl<'a, T> ConstIntoIter for RChunksExact<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } /// Const equivalent of `core::iter::Rev` /// /// This is constructed with [`rchunks_exact`] like this: /// ```rust /// # let slice = &[3]; /// # let _ = /// konst::slice::rchunks_exact(slice, 1).rev() /// # ; /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RChunksExactRev<'a, T> { slice: &'a [T], rem: &'a [T], chunk_size: usize, } impl<'a, T> ConstIntoIter for RChunksExactRev<'a, T> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a [T]; } impl<'a, T> RChunksExact<'a, T> { rchunks_exact_shared! {is_forward = true} } impl<'a, T> RChunksExactRev<'a, T> { rchunks_exact_shared! {is_forward = false} } } #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use requires_rust_1_64::*; konst-0.3.16/src/slice.rs000064400000000000000000000120441046102023000133060ustar 00000000000000//! `const fn` equivalents of slice methods. //! //! # Removed in 0.3.0 //! //! These functions were removed in 0.3.0 because there is an equivalent //! const fn in the standard library: //! //! - `first` //! - `last` //! - `split_first` //! - `split_last` //! //! //! /// `const fn`s for comparing slices for equality and ordering. #[cfg(feature = "cmp")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] pub mod cmp; mod bytes_pattern; mod slice_as_chunks; mod slice_concatenation; mod slice_const_methods; #[cfg(feature = "iter")] mod slice_iter_methods; pub use bytes_pattern::BytesPattern; pub(crate) use bytes_pattern::PatternNorm; pub use self::slice_as_chunks::*; pub use self::slice_concatenation::*; pub use self::slice_const_methods::*; #[cfg(feature = "iter")] pub use slice_iter_methods::*; __declare_slice_cmp_fns! { import_path = "konst", ( /// /// # Example /// , /// ```rust /// use konst::slice::eq_bytes; /// /// const FOO: &[u8] = b"foo"; /// const BAR: &[u8] = b"fooooo"; /// const BAZ: &[u8] = b"bar"; /// /// /// const FOO_EQ_FOO: bool = eq_bytes(FOO, FOO); /// assert!( FOO_EQ_FOO ); /// /// const FOO_EQ_BAR: bool = eq_bytes(FOO, BAR); /// assert!( !FOO_EQ_BAR ); /// /// const FOO_EQ_BAZ: bool = eq_bytes(FOO, BAZ); /// assert!( !FOO_EQ_BAZ ); /// /// ``` /// , /// ```rust /// use konst::slice::cmp_bytes; /// /// use std::cmp::Ordering; /// /// const FOO: &[u8] = b"foo"; /// const BAR: &[u8] = b"fooooo"; /// const BAZ: &[u8] = b"bar"; /// /// /// const FOO_CMP_FOO: Ordering = cmp_bytes(FOO, FOO); /// assert_eq!(FOO_CMP_FOO, Ordering::Equal); /// /// const FOO_CMP_BAR: Ordering = cmp_bytes(FOO, BAR); /// assert_eq!(FOO_CMP_BAR, Ordering::Less); /// /// const FOO_CMP_BAZ: Ordering = cmp_bytes(FOO, BAZ); /// assert_eq!(FOO_CMP_BAZ, Ordering::Greater); /// /// ``` /// , u8, eq_bytes, cmp_bytes, ) } __declare_fns_with_docs! { (Option<&'a [u8]>, (eq_option_bytes, cmp_option_bytes)) docs(default) macro = __impl_option_cmp_fns!( for['a,] params(l, r) eq_comparison = eq_bytes(l, r), cmp_comparison = cmp_bytes(l, r), parameter_copyability = copy, ), } /// The error produced by trying to convert from /// `&[T]` to `&[T; N]`, or from `&mut [T]` to `&mut [T; N]`. #[doc(inline)] pub use konst_kernel::slice::slice_for_konst::TryIntoArrayError; /// Tries to convert from `&[T]` to `&[T; N]`. /// /// Returns an `Err(TryIntoArrayError{..})` when the slice doesn't match the expected length. /// /// # Example /// /// ```rust /// use konst::{ /// slice::{TryIntoArrayError, try_into_array}, /// result, /// unwrap_ctx, /// }; /// /// /// const fn arr_5() -> Option<&'static [u64; 5]> { /// let slice: &[u64] = &[1, 10, 100, 1000, 10000]; /// /// // Passing the length explicitly to the function /// result::ok!(try_into_array::<_, 5>(slice)) /// } /// /// assert_eq!(arr_5(), Some(&[1, 10, 100, 1000, 10000])); /// /// /// const fn err() -> Result<&'static [u64; 5], TryIntoArrayError> { /// let slice: &[u64] = &[]; /// /// // Letting the function infer the length of the array, /// try_into_array(slice) /// } /// /// assert!(err().is_err()); /// /// /// const fn arr_3() -> &'static [u64; 3] { /// let slice: &[u64] = &[3, 5, 8]; /// /// let array = unwrap_ctx!(try_into_array(slice)); /// /// // You can destructure the array into its elements like this /// let [a, b, c] = *array; /// /// array /// } /// /// assert_eq!(arr_3(), &[3, 5, 8]); /// /// ``` /// /// [`try_into_array`]: ./macro.try_into_array.html #[doc(inline)] pub use konst_kernel::slice::slice_for_konst::try_into_array_func as try_into_array; /// Tries to convert from `&mut [T]` to `&mut [T; N]`. /// /// Returns an `Err(TryIntoArrayError{..})` when the slice doesn't match the expected length. /// /// # Example /// /// ```rust /// use konst::{slice, unwrap_ctx}; /// /// const fn mut_array_from(slice: &mut [u8], from: usize) -> &mut [u8; LEN] { /// let sliced = slice::slice_range_mut(slice, from, from + LEN); /// unwrap_ctx!(slice::try_into_array_mut(sliced)) /// } /// /// # fn main() { /// /// let slice = &mut [3, 5, 8, 13, 21, 34, 55, 89, 144, 233]; /// /// let foo: &mut [u8; 2] = mut_array_from(slice, 0); /// assert_eq!(foo, &mut [3, 5]); /// /// let bar: &mut [u8; 3] = mut_array_from(slice, 2); /// assert_eq!(bar, &mut [8, 13, 21]); /// /// let baz: &mut [u8; 4] = mut_array_from(slice, 4); /// assert_eq!(baz, &mut [21, 34, 55, 89]); /// /// # } /// ``` /// #[cfg(feature = "rust_1_83")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))] #[doc(inline)] pub use konst_kernel::slice::slice_for_konst::try_into_array_mut_func as try_into_array_mut; konst-0.3.16/src/string/chars_methods.rs000064400000000000000000000163221046102023000163430ustar 00000000000000use crate::{ iter::{ConstIntoIter, IsIteratorKind}, string, }; use konst_kernel::{ iterator_shared, string::{__find_next_char_boundary, __find_prev_char_boundary}, }; /// Converts a string spanning one character to its char value /// (as a u32) pub(super) const fn string_to_usv(s: &str) -> u32 { match *s.as_bytes() { [a] => a as _, [a, b] => ((a as u32 & 0x1F) << 6) | (b as u32 & 0x7F), [a, b, c] => ((a as u32 & 0xF) << 12) | ((b as u32 & 0x3F) << 6) | (c as u32 & 0x3F), [a, b, c, d] => { ((a as u32 & 0x7) << 18) | ((b as u32 & 0x3F) << 12) | ((c as u32 & 0x3F) << 6) | (d as u32 & 0x3F) } _ => { #[cfg(feature = "debug")] { panic!("string must be a single char long") } #[cfg(not(feature = "debug"))] { 0 } } } } pub(super) const fn string_to_char(s: &str) -> char { let c: u32 = string_to_usv(s); unsafe { crate::chr::from_u32_unchecked(c) } } /// Cosnt equivalent of [`str::chars`]. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const CHARS: &[char] = &collect_const!(char => string::chars("bar")); /// const REV: &[char] = &collect_const!(char => string::chars("bar").rev()); /// /// assert_eq!(CHARS, &['b', 'a', 'r']); /// assert_eq!(REV, &['r', 'a', 'b']); /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn chars(string: &str) -> Chars<'_> { Chars { this: string } } /// Const equivalent of [`core::str::Chars`] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct Chars<'a> { this: &'a str, } /// Const equivalent of `core::iter::Rev>` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RChars<'a> { this: &'a str, } impl ConstIntoIter for Chars<'_> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = char; } impl ConstIntoIter for RChars<'_> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = char; } macro_rules! chars_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = char, iter_forward = Chars<'a>, iter_reversed = RChars<'a>, next(self){ if self.this.is_empty() { return None } let split_at = __find_next_char_boundary(self.this.as_bytes(), 0); let (prev, next) = string::split_at(self.this, split_at); Some((string_to_char(prev), Self{this: next})) }, next_back{ if self.this.is_empty() { return None } let split_at = __find_prev_char_boundary(self.this.as_bytes(), self.this.len()); let (prev, next) = string::split_at(self.this, split_at); Some((string_to_char(next), Self{this: prev})) }, fields = {this}, } }; } impl<'a> Chars<'a> { chars_shared! {is_forward = true} /// Gets a string slice to the yet-to-be-iterated characters. /// /// # Example /// /// ```rust /// use konst::{for_range, option, string}; /// /// const S: &str = { /// let mut iter = string::chars("hello world"); /// for_range!{_ in 0..6 => /// (_, iter) = option::unwrap!(iter.next()); /// } /// iter.as_str() /// }; /// /// assert_eq!(S, "world") /// /// ``` /// pub const fn as_str(&self) -> &'a str { self.this } } impl<'a> RChars<'a> { chars_shared! {is_forward = false} } //////////////////////////////////////////////////////////////////////////////// /// Cosnt equivalent of [`str::char_indices`]. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const CHARS: &[(usize, char)] = /// &collect_const!((usize, char) => string::char_indices("个bar人")); /// /// const REV: &[(usize, char)] = /// &collect_const!((usize, char) => string::char_indices("个bar人").rev()); /// /// assert_eq!(CHARS, &[(0, '个'), (3, 'b'), (4, 'a'), (5, 'r'), (6, '人')]); /// assert_eq!(REV, &[(6, '人'), (5, 'r'), (4, 'a'), (3, 'b'), (0, '个')]); /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn char_indices(string: &str) -> CharIndices<'_> { CharIndices { this: string, start_offset: 0, } } /// Const equivalent of [`core::str::CharIndices`] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct CharIndices<'a> { this: &'a str, start_offset: usize, } /// Const equivalent of `core::iter::Rev>` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RCharIndices<'a> { this: &'a str, start_offset: usize, } impl ConstIntoIter for CharIndices<'_> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = (usize, char); } impl ConstIntoIter for RCharIndices<'_> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = (usize, char); } macro_rules! chars_shared { (is_forward = $is_forward:ident) => { iterator_shared! { is_forward = $is_forward, item = (usize, char), iter_forward = CharIndices<'a>, iter_reversed = RCharIndices<'a>, next(self){ if self.this.is_empty() { return None } let split_at = __find_next_char_boundary(self.this.as_bytes(), 0); let (prev, next) = string::split_at(self.this, split_at); let ret = Self { this: next, start_offset: self.start_offset + split_at, }; Some(((self.start_offset, string_to_char(prev)), ret)) }, next_back{ if self.this.is_empty() { return None } let split_at = __find_prev_char_boundary(self.this.as_bytes(), self.this.len()); let (prev, next) = string::split_at(self.this, split_at); let ret = Self { this: prev, start_offset: self.start_offset, }; Some(((self.start_offset + split_at, string_to_char(next)), ret)) }, fields = {this, start_offset}, } }; } impl<'a> CharIndices<'a> { chars_shared! {is_forward = true} /// Gets a string slice to the yet-to-be-iterated characters. /// /// # Example /// /// ```rust /// use konst::{for_range, option, string}; /// /// const S: &str = { /// let mut iter = string::char_indices("this is fine"); /// for_range!{_ in 0..8 => /// (_, iter) = option::unwrap!(iter.next()); /// } /// iter.as_str() /// }; /// /// assert_eq!(S, "fine") /// /// ``` /// pub const fn as_str(&self) -> &'a str { self.this } } impl<'a> RCharIndices<'a> { chars_shared! {is_forward = false} } konst-0.3.16/src/string/concatenation.rs000064400000000000000000000052071046102023000163450ustar 00000000000000/// Macro equivalent of `<[&str]>::concat`, which takes a constant as an argument. /// /// This acts like a compile-time-evaluated version of this function: /// ```rust /// # trait StrOrChar: Copy {} /// pub const fn str_concat(strings: &'static [impl StrOrChar]) -> &'static str /// # { "" } /// ``` /// /// Where `impl StrOrChar` is either a `&'static str` or `char` /// /// # Example /// /// ```rust /// use konst::string::str_concat; /// /// { /// const S: &[&str] = &["these ", "are ", "words"]; /// assert_eq!(str_concat!(S), "these are words"); /// /// assert_eq!(str_concat!(&[]), ""); /// /// assert_eq!(str_concat!(&["foo", "bar", "baz"]), "foobarbaz"); /// } /// /// { /// const C: &[char] = &['c', 'h', 'a', 'r', 's']; /// assert_eq!(str_concat!(C), "chars"); /// /// assert_eq!(str_concat!(&['q'; 10]), "qqqqqqqqqq"); /// } /// /// /// ``` pub use konst_kernel::string_concat as str_concat; /// Macro equivalent of `<[&str]>::join`, which takes constants as arguments. /// /// This acts like a compile-time-evaluated version of this function: /// ```rust /// # trait StrOrChar: Copy {} /// pub const fn str_join( /// delimiter: impl StrOrChar, /// strings: &'static [&'static str], /// ) -> &'static str /// # { "" } /// ``` /// /// Where `impl StrOrChar` is either a `&'static str` or `char` /// /// # Example /// /// ```rust /// use konst::string::str_join; /// /// { /// const COMMA: &str = ","; /// const S: &[&str] = &["these", "are", "words"]; /// assert_eq!(str_join!(COMMA, S), "these,are,words"); /// } /// /// assert_eq!(str_join!(",", &[]), ""); /// /// assert_eq!(str_join!(" ", &["foo", "bar", "baz"]), "foo bar baz"); /// /// // char separator /// assert_eq!(str_join!(' ', &["foo", "bar", "baz"]), "foo bar baz"); /// /// ``` pub use konst_kernel::string_join as str_join; /// Makes a `&'static str` from an const iterator over `&str`s or `char`s /// /// # Example /// /// ### Iterator over strings /// /// ```rust /// use konst::string; /// /// const S: &str = string::from_iter!( /// &["foo", "bar", "baz"], /// flat_map(|s| { /// // By value iteration over arrays isn't supported, /// // but by-reference iteration is supported /// &[*s, ", "] /// }) /// ); /// /// assert_eq!(S, "foo, bar, baz, "); /// /// ``` /// /// ### Iterator over chars /// /// ```rust /// use konst::{iter, string}; /// /// const S: &str = string::from_iter!('a'..='z'); /// /// assert_eq!(S, "abcdefghijklmnopqrstuvwxyz"); /// /// ``` #[cfg(feature = "iter")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub use konst_kernel::str_from_iter as from_iter; konst-0.3.16/src/string/pattern.rs000064400000000000000000000052011046102023000151670ustar 00000000000000use crate::{ chr, polymorphism::{HasTypeWitness, MakeTypeWitness, TypeEq, TypeWitnessTypeArg}, }; /// A string pattern. /// /// Types that implement this trait can be used to search into a string. /// /// This trait can only be implemented in the `konst` crate. /// pub trait Pattern<'a>: HasTypeWitness> + Copy + Sized {} macro_rules! declare_patterns { ($(( $variant:ident, $ty:ty, $normalized:ty, $index:expr, |$param:tt| $normalizer:expr ),)*) => ( pub struct PatternInput<'a, P: Pattern<'a>>(PatternInputInner<'a, P>); enum PatternInputInner<'a, P: Pattern<'a>> { $( $variant {te: TypeEq}, )* } impl<'a, Arg> TypeWitnessTypeArg for PatternInput<'a, Arg> where Arg: Pattern<'a> { type Arg = Arg; } $( impl<'a> MakeTypeWitness for PatternInput<'a, $ty> { const MAKE: Self = PatternInput(PatternInputInner::$variant{ te: TypeEq::NEW, }); } impl<'a> Pattern<'a> for $ty {} )* #[derive(Copy, Clone)] pub(crate) enum PatternNorm<'a, P: Pattern<'a>> { $( $variant{ val: $normalized, te: TypeEq, }, )* } impl<'a, P: Pattern<'a>> PatternNorm<'a, P> { pub(crate) const fn new(pattern: P) -> Self where P: Pattern<'a> { match P::WITNESS.0 { $( PatternInputInner::$variant{te} => { let $param = te.to_right(pattern); PatternNorm::$variant{val: $normalizer, te} } )* } } pub(crate) const fn as_str(&self) -> &str { match self { PatternNorm::Str{val, te} => te.reachability_hint(*val), PatternNorm::Char{val, te} => te.reachability_hint(val.as_str()), } } pub(crate) const fn as_bytes(&self) -> &[u8] { match self { PatternNorm::Str{val, te} => te.reachability_hint(val.as_bytes()), PatternNorm::Char{val, te} => te.reachability_hint(val.as_bytes()), } } } ) } declare_patterns! { (Str, &'a str, &'a str, 0, |x| x), (Char, char, chr::Utf8Encoded, 1, |char| chr::encode_utf8(char)), } konst-0.3.16/src/string/priv_string_tests.rs000064400000000000000000000031041046102023000173020ustar 00000000000000#[cfg(feature = "iter")] use crate::string::chars_methods::{string_to_char, string_to_usv}; // index: 00 char: '🧡' len_utf8: 4 // index: 04 char: '🧠' len_utf8: 4 // index: 08 char: '₀' len_utf8: 3 // index: 11 char: '₁' len_utf8: 3 // index: 14 char: 'o' len_utf8: 1 // index: 15 char: 'ñ' len_utf8: 2 // index: 17 char: '个' len_utf8: 3 const S: &str = "🧡🧠₀₁oñ个"; const B: &[u8] = S.as_bytes(); #[test] #[should_panic] fn invalid_start() { // SAFETY: this is a slice of a string let _ = unsafe { super::__from_u8_subslice_of_str(&B[1..]) }; } #[test] #[should_panic] fn invalid_end() { // SAFETY: this is a slice of a string let _ = unsafe { super::__from_u8_subslice_of_str(&B[..B.len() - 1]) }; } #[test] #[should_panic] fn invalid_both() { // SAFETY: this is a slice of a string let _ = unsafe { super::__from_u8_subslice_of_str(&B[1..B.len() - 1]) }; } #[test] #[cfg(feature = "iter")] fn str_to_char_test() { assert_eq!(string_to_char("🧡"), '🧡'); assert_eq!(string_to_char("🧠"), '🧠'); assert_eq!(string_to_char("₀"), '₀'); assert_eq!(string_to_char("₁"), '₁'); assert_eq!(string_to_char("o"), 'o'); assert_eq!(string_to_char("ñ"), 'ñ'); assert_eq!(string_to_char("个"), '个'); } #[test] #[cfg(feature = "iter")] #[cfg(not(miri))] fn str_to_codepoint_test() { for c in '\0'..=char::MAX { let mut arr = [0u8; 8]; let string = c.encode_utf8(&mut arr); let found = core::char::from_u32(string_to_usv(string)).unwrap(); assert_eq!(found, c, "{c:?}"); } } konst-0.3.16/src/string/split_n_items.rs000064400000000000000000000000001046102023000163530ustar 00000000000000konst-0.3.16/src/string/split_once.rs000064400000000000000000000051351046102023000156570ustar 00000000000000use crate::string::{self, str_from, str_up_to, Pattern, PatternNorm}; /// A const-equivalent of the [`str::split_once`] method. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert_eq!(string::split_once("", "-"), None); /// assert_eq!(string::split_once("foo", "-"), None); /// assert_eq!(string::split_once("foo-", "-"), Some(("foo", ""))); /// assert_eq!(string::split_once("foo-bar", "-"), Some(("foo", "bar"))); /// assert_eq!(string::split_once("foo-bar-baz", "-"), Some(("foo", "bar-baz"))); /// /// assert_eq!(string::split_once("foo,bar", ","), Some(("foo", "bar"))); /// assert_eq!(string::split_once("foo,bar,baz", ","), Some(("foo", "bar,baz"))); /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn split_once<'a, 'p, P>(this: &'a str, delim: P) -> Option<(&'a str, &'a str)> where P: Pattern<'p>, { let delim = PatternNorm::new(delim); let delim = delim.as_str(); if delim.is_empty() { // using split_at so that the pointer points within the string Some(string::split_at(this, 0)) } else { crate::option::map! { string::find(this, delim), |pos| (str_up_to(this, pos), str_from(this, pos + delim.len())) } } } /// A const-equivalent of the [`str::rsplit_once`] method. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert_eq!(string::rsplit_once("", "-"), None); /// assert_eq!(string::rsplit_once("foo", "-"), None); /// assert_eq!(string::rsplit_once("foo-", "-"), Some(("foo", ""))); /// assert_eq!(string::rsplit_once("-foo", "-"), Some(("","foo"))); /// assert_eq!(string::rsplit_once("foo-bar", "-"), Some(("foo", "bar"))); /// assert_eq!(string::rsplit_once("foo-bar-baz", "-"), Some(("foo-bar", "baz"))); /// /// assert_eq!(string::rsplit_once("foo,bar", ','), Some(("foo", "bar"))); /// assert_eq!(string::rsplit_once("foo,bar,baz", ','), Some(("foo,bar", "baz"))); /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn rsplit_once<'a, 'p, P>(this: &'a str, delim: P) -> Option<(&'a str, &'a str)> where P: Pattern<'p>, { let delim = PatternNorm::new(delim); let delim = delim.as_str(); if delim.is_empty() { // using split_at so that the pointer points within the string Some(string::split_at(this, this.len())) } else { crate::option::map! { string::rfind(this, delim), |pos| (str_up_to(this, pos), str_from(this, pos + delim.len())) } } } konst-0.3.16/src/string/split_terminator_items.rs000064400000000000000000000173001046102023000203150ustar 00000000000000use crate::{ iter::{ConstIntoIter, IsIteratorKind}, string::{self, str_from, str_up_to, Pattern, PatternNorm}, }; use konst_kernel::iterator_shared; /// Const equivalent of [`str::split_terminator`], which only takes a `&str` delimiter. /// /// This does the same as [`split`](crate::string::split), /// except that, if the string after the last delimiter is empty, it is skipped. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const STRS: [&str; 3] = collect_const!(&str => /// string::split_terminator("foo,bar,baz,", ',') /// ); /// /// assert_eq!(STRS, ["foo", "bar", "baz"]); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn split_terminator<'a, 'p, P>(this: &'a str, delim: P) -> SplitTerminator<'a, 'p, P> where P: Pattern<'p>, { let delim = PatternNorm::new(delim); SplitTerminator { this, state: if delim.as_str().is_empty() { State::Empty(EmptyState::Start) } else { State::Normal { delim } }, } } /// Const equivalent of [`str::rsplit_terminator`]. /// /// This does the same as [`rsplit`](crate::string::rsplit), /// except that, if the string before the first delimiter is empty, it is skipped. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const STRS: [&str; 3] = collect_const!(&str => /// string::rsplit_terminator(":foo:bar:baz", ":") /// ); /// /// assert_eq!(STRS, ["baz", "bar", "foo"]); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn rsplit_terminator<'a, 'p, P>(this: &'a str, delim: P) -> RSplitTerminator<'a, 'p, P> where P: Pattern<'p>, { let SplitTerminator { this, state } = split_terminator(this, delim); RSplitTerminator { this, state } } #[derive(Copy, Clone)] enum State<'p, P: Pattern<'p>> { Normal { delim: PatternNorm<'p, P> }, Empty(EmptyState), } #[derive(Copy, Clone)] enum EmptyState { Start, Continue, } /// Const equivalent of `core::str::SplitTerminator<'a, P>` /// /// This is constructed with [`split_terminator`] like this: /// ```rust /// # let string = ""; /// # let delim = ""; /// # let _: konst::string::SplitTerminator<'_, '_, &str> = /// konst::string::split_terminator(string, delim) /// # ; /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct SplitTerminator<'a, 'p, P: Pattern<'p>> { this: &'a str, state: State<'p, P>, } impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for SplitTerminator<'a, 'p, P> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a str; } impl<'a, 'p, P: Pattern<'p>> SplitTerminator<'a, 'p, P> { iterator_shared! { is_forward = true, item = &'a str, iter_forward = SplitTerminator<'a, 'p, P>, next(self){ let Self { this, state, } = self; match state { State::Empty(EmptyState::Start) => { self.state = State::Empty(EmptyState::Continue); Some(("", self)) } _ if this.is_empty() => { None } State::Normal{delim} => { let delim = delim.as_str(); let (next, ret) = match string::find(this, delim) { Some(pos) => (pos + delim.len(), pos), None => (this.len(), this.len()), }; self.this = str_from(this, next); Some((str_up_to(this, ret), self)) } State::Empty(EmptyState::Continue) => { use konst_kernel::string::__find_next_char_boundary; let next_char = __find_next_char_boundary(self.this.as_bytes(), 0); let (next_char, rem) = string::split_at(self.this, next_char); self.this = rem; Some((next_char, self)) } } }, fields = {this, state}, } /// Gets the remainder of the string. /// /// # Example /// /// ```rust /// let iter = konst::string::split_terminator("foo,bar,baz,", ","); /// assert_eq!(iter.remainder(), "foo,bar,baz,"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "foo"); /// assert_eq!(iter.remainder(), "bar,baz,"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "bar"); /// assert_eq!(iter.remainder(), "baz,"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "baz"); /// assert_eq!(iter.remainder(), ""); /// /// ``` pub const fn remainder(&self) -> &'a str { self.this } } /// Const equivalent of `core::str::RSplitTerminator<'a, P>` /// /// This is constructed with [`rsplit_terminator`] like this: /// ```rust /// # let string = ""; /// # let delim = ""; /// # let _: konst::string::RSplitTerminator<'_, '_, &str> = /// konst::string::rsplit_terminator(string, delim) /// # ; /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RSplitTerminator<'a, 'p, P: Pattern<'p>> { this: &'a str, state: State<'p, P>, } impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for RSplitTerminator<'a, 'p, P> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a str; } impl<'a, 'p, P: Pattern<'p>> RSplitTerminator<'a, 'p, P> { iterator_shared! { is_forward = true, item = &'a str, iter_forward = RSplitTerminator<'a, 'p>, next(self){ let Self { this, state, } = self; match state { State::Empty(EmptyState::Start) => { self.state = State::Empty(EmptyState::Continue); Some(("", self)) } _ if this.is_empty() => { None } State::Normal{delim} => { let delim = delim.as_str(); let (next, ret) = match string::rfind(this, delim) { Some(pos) => (pos, pos + delim.len()), None => (0, 0), }; self.this = str_up_to(this, next); Some((str_from(this, ret), self)) } State::Empty(EmptyState::Continue) => { use konst_kernel::string::__find_prev_char_boundary; let bytes = self.this.as_bytes(); let next_char = __find_prev_char_boundary(bytes, bytes.len()); let (rem, next_char) = string::split_at(self.this, next_char); self.this = rem; Some((next_char, self)) } } }, fields = {this, state}, } /// Gets the remainder of the string. /// /// # Example /// /// ```rust /// let iter = konst::string::rsplit_terminator("=foo=bar=baz", "="); /// assert_eq!(iter.remainder(), "=foo=bar=baz"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "baz"); /// assert_eq!(iter.remainder(), "=foo=bar"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "bar"); /// assert_eq!(iter.remainder(), "=foo"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "foo"); /// assert_eq!(iter.remainder(), ""); /// /// ``` pub const fn remainder(&self) -> &'a str { self.this } } konst-0.3.16/src/string/splitting.rs000064400000000000000000000205111046102023000155300ustar 00000000000000use crate::{ iter::{ConstIntoIter, IsIteratorKind}, string::{self, str_from, str_up_to, Pattern, PatternNorm}, }; use konst_kernel::iterator_shared; /// Const equivalent of [`str::split`]. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const STRS0: [&str; 3] = collect_const!(&str => string::split("foo-bar-baz", "-")); /// const STRS1: [&str; 3] = collect_const!(&str => string::split("these are spaced", ' ')); /// /// assert_eq!(STRS0, ["foo", "bar", "baz"]); /// assert_eq!(STRS1, ["these", "are", "spaced"]); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn split<'a, 'p, P>(this: &'a str, delim: P) -> Split<'a, 'p, P> where P: Pattern<'p>, { let delim = PatternNorm::new(delim); Split { this, state: if delim.as_str().is_empty() { State::Empty(EmptyState::Start) } else { State::Normal { delim } }, } } /// Const equivalent of [`str::rsplit`]. /// /// This takes [`Pattern`] implementors as the delimiter. /// /// # Example /// /// ```rust /// use konst::string; /// use konst::iter::collect_const; /// /// const STRS0: [&str; 3] = collect_const!(&str => string::rsplit("foo-bar-baz", "-")); /// const STRS1: [&str; 3] = collect_const!(&str => string::rsplit("these are spaced", ' ')); /// /// assert_eq!(STRS0, ["baz", "bar", "foo"]); /// assert_eq!(STRS1, ["spaced", "are", "these"]); /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub const fn rsplit<'a, 'p, P>(this: &'a str, delim: P) -> RSplit<'a, 'p, P> where P: Pattern<'p>, { split(this, delim).rev() } #[derive(Copy, Clone)] enum State<'p, P: Pattern<'p>> { Normal { delim: PatternNorm<'p, P> }, Empty(EmptyState), Finished, } #[derive(Copy, Clone)] enum EmptyState { Start, Continue, } macro_rules! split_shared { (is_forward = $is_forward:ident) => { const fn next_from_empty(mut self, es: EmptyState) -> Option<(&'a str, Self)> { match es { EmptyState::Start => { self.state = State::Empty(EmptyState::Continue); Some(("", self)) } EmptyState::Continue => { use konst_kernel::string::__find_next_char_boundary; let this = self.this; if this.is_empty() { self.state = State::Finished; } let next_char = __find_next_char_boundary(this.as_bytes(), 0); let (next_char, rem) = string::split_at(this, next_char); self.this = rem; Some((next_char, self)) } } } const fn next_back_from_empty(mut self, es: EmptyState) -> Option<(&'a str, Self)> { match es { EmptyState::Start => { self.state = State::Empty(EmptyState::Continue); Some(("", self)) } EmptyState::Continue => { use konst_kernel::string::__find_prev_char_boundary; let this = self.this; if self.this.is_empty() { self.state = State::Finished; } let next_char = __find_prev_char_boundary(this.as_bytes(), this.len()); let (rem, next_char) = string::split_at(this, next_char); self.this = rem; Some((next_char, self)) } } } iterator_shared! { is_forward = $is_forward, item = &'a str, iter_forward = Split<'a, 'p, P>, iter_reversed = RSplit<'a, 'p, P>, next(self){ let Self { this, state, } = self; match state { State::Normal{delim} => { let delim = delim.as_str(); match string::find(this, delim) { Some(pos) => { self.this = str_from(this, pos + delim.len()); Some((str_up_to(this, pos), self)) } None => { self.this = ""; self.state = State::Finished; Some((this, self)) } } } State::Empty(es) => self.next_from_empty(es), State::Finished => None, } }, next_back{ let Self { this, state, } = self; match state { State::Normal{delim} => { let delim = delim.as_str(); match string::rfind(this, delim) { Some(pos) => { self.this = str_up_to(this, pos); Some((str_from(this, pos + delim.len()), self)) } None => { self.this = ""; self.state = State::Finished; Some((this, self)) } } } State::Empty(es) => self.next_back_from_empty(es), State::Finished => None, } }, fields = {this, state}, } }; } /// Const equivalent of `core::str::Split<'a, P>` /// /// This is constructed with [`split`] like this: /// ```rust /// # let string = ""; /// # let delim = ""; /// # let _ = /// konst::string::split(string, delim) /// # ; /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct Split<'a, 'p, P: Pattern<'p>> { this: &'a str, state: State<'p, P>, } impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for Split<'a, 'p, P> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a str; } impl<'a, 'p, P: Pattern<'p>> Split<'a, 'p, P> { split_shared! {is_forward = true} /// Gets the remainder of the string. /// /// # Example /// /// ```rust /// let iter = konst::string::split("foo-bar-baz", "-"); /// assert_eq!(iter.remainder(), "foo-bar-baz"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "foo"); /// assert_eq!(iter.remainder(), "bar-baz"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "bar"); /// assert_eq!(iter.remainder(), "baz"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "baz"); /// assert_eq!(iter.remainder(), ""); /// /// ``` pub const fn remainder(&self) -> &'a str { self.this } } /// Const equivalent of `core::str::RSplit<'a, P>` /// /// This is constructed with [`rsplit`] like this: /// ```rust /// # let string = ""; /// # let delim = ""; /// # let _ = /// konst::string::rsplit(string, delim) /// # ; /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))] pub struct RSplit<'a, 'p, P: Pattern<'p>> { this: &'a str, state: State<'p, P>, } impl<'a, 'p, P: Pattern<'p>> ConstIntoIter for RSplit<'a, 'p, P> { type Kind = IsIteratorKind; type IntoIter = Self; type Item = &'a str; } impl<'a, 'p, P: Pattern<'p>> RSplit<'a, 'p, P> { split_shared! {is_forward = false} /// Gets the remainder of the string. /// /// # Example /// /// ```rust /// let iter = konst::string::rsplit("foo-bar-baz", "-"); /// assert_eq!(iter.remainder(), "foo-bar-baz"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "baz"); /// assert_eq!(iter.remainder(), "foo-bar"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "bar"); /// assert_eq!(iter.remainder(), "foo"); /// /// let (elem, iter) = iter.next().unwrap(); /// assert_eq!(elem, "foo"); /// assert_eq!(iter.remainder(), ""); /// /// ``` pub const fn remainder(&self) -> &'a str { self.this } } konst-0.3.16/src/string.rs000064400000000000000000000651631046102023000135270ustar 00000000000000//! `const fn` equivalents of `str` methods. //! #[cfg(feature = "iter")] mod chars_methods; #[cfg(feature = "iter")] pub use chars_methods::*; mod concatenation; pub use concatenation::*; #[cfg(test)] mod priv_string_tests; mod pattern; use core::fmt::{self, Debug, Display}; pub use self::pattern::Pattern; pub(crate) use self::pattern::PatternNorm; mod split_once; pub use split_once::*; #[cfg(feature = "iter")] mod splitting; #[cfg(feature = "iter")] pub use splitting::*; #[cfg(feature = "iter")] mod split_terminator_items; #[cfg(feature = "iter")] pub use split_terminator_items::*; use konst_kernel::string::__is_char_boundary_bytes; __declare_string_cmp_fns! { import_path = "konst", equality_fn = eq_str, ordering_fn = cmp_str, ordering_fn_inner = cmp_str_inner, } #[cfg(feature = "cmp")] __declare_fns_with_docs! { (Option<&'a str>, (eq_option_str, cmp_option_str)) docs(default) macro = __impl_option_cmp_fns!( #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))] for['a,] params(l, r) eq_comparison = crate::cmp::CmpWrapper(l).const_eq(r), cmp_comparison = crate::cmp::CmpWrapper(l).const_cmp(r), parameter_copyability = copy, ), } /// Delegates to [`core::str::from_utf8`], /// wrapping the error to provide a `panic` method for use in [`unwrap_ctx`] /// /// # Example /// /// ### Basic /// /// ```rust /// use konst::{ /// result::unwrap_ctx, /// string, /// }; /// /// const STR: &str = unwrap_ctx!(string::from_utf8(b"foo bar")); /// /// assert_eq!(STR, "foo bar") /// ``` /// /// ### Compile-time error /// /// ```compile_fail /// use konst::{ /// result::unwrap_ctx, /// string, /// }; /// /// const _: &str = unwrap_ctx!(string::from_utf8(&[255, 255, 255])); /// ``` /// /// ```text /// error[E0080]: evaluation of constant value failed /// --> src/string.rs:88:17 /// | /// 9 | const _: &str = unwrap_ctx!(string::from_utf8(&[255, 255, 255])); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'invalid utf-8 sequence of 1 bytes from index 0', src/string.rs:9:17 /// | /// = note: this error originates in the macro `unwrap_ctx` (in Nightly builds, run with -Z macro-backtrace for more info) /// /// ``` /// /// [`unwrap_ctx`]: crate::result::unwrap_ctx pub const fn from_utf8(slice: &[u8]) -> Result<&str, Utf8Error> { match core::str::from_utf8(slice) { Ok(x) => Ok(x), Err(e) => Err(Utf8Error(e)), } } /// Wrapper around [`core::str::Utf8Error`] /// to provide a `panic` method for use in [`unwrap_ctx`], /// returned by [`from_utf8`](crate::string::from_utf8). /// /// [`unwrap_ctx`]: crate::result::unwrap_ctx #[derive(Copy, Clone)] pub struct Utf8Error(pub core::str::Utf8Error); impl Utf8Error { /// Panics with a `Display` formatted error message #[track_caller] pub const fn panic(self) -> ! { let pvs = const_panic::StdWrapper(&self.0).to_panicvals(const_panic::FmtArg::DISPLAY); const_panic::concat_panic(&[&pvs]) } } impl Debug for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&self.0, f) } } impl Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } /// A const equivalent of /// [`str::starts_with`](https://doc.rust-lang.org/std/primitive.str.html#method.starts_with) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert!( string::starts_with("foo,bar,baz", "foo,")); /// /// assert!(!string::starts_with("foo,bar,baz", "bar")); /// assert!(!string::starts_with("foo,bar,baz", "baz")); /// /// ``` /// #[inline(always)] pub const fn starts_with<'a, P>(left: &str, pat: P) -> bool where P: Pattern<'a>, { let pat = PatternNorm::new(pat); crate::slice::__bytes_start_with(left.as_bytes(), pat.as_bytes()) } /// A const equivalent of /// [`str::ends_with`](https://doc.rust-lang.org/std/primitive.str.html#method.ends_with) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert!( string::ends_with("foo,bar,baz", ",baz")); /// assert!( string::ends_with("abc...z", 'z')); /// /// assert!(!string::ends_with("foo,bar,baz", "bar")); /// assert!(!string::ends_with("foo,bar,baz", "foo")); /// assert!(!string::ends_with("abc", 'z')); /// /// ``` /// #[inline(always)] pub const fn ends_with<'a, P>(left: &str, pat: P) -> bool where P: Pattern<'a>, { let pat = PatternNorm::new(pat); crate::slice::__bytes_end_with(left.as_bytes(), pat.as_bytes()) } /// A const equivalent of /// [`str::find`](https://doc.rust-lang.org/std/primitive.str.html#method.find) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert_eq!(string::find("foo-bar-baz", 'q'), None); /// assert_eq!(string::find("foo-bar-baz", '-'), Some(3)); /// /// assert_eq!(string::find("foo-bar-baz-foo", "qux"), None); /// assert_eq!(string::find("foo-bar-baz-foo", "foo"), Some(0)); /// assert_eq!(string::find("foo-bar-baz-foo-bar", "bar"), Some(4)); /// assert_eq!(string::find("foo-the-baz-foo-bar", "bar"), Some(16)); /// /// ``` /// #[inline] pub const fn find<'a, P>(left: &str, pat: P) -> Option where P: Pattern<'a>, { let pat = PatternNorm::new(pat); crate::slice::__bytes_find(left.as_bytes(), pat.as_bytes()) } /// A const equivalent of /// [`str::contains`](https://doc.rust-lang.org/std/primitive.str.html#method.contains) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert!(string::contains("foo-bar-baz", '-')); /// assert!(!string::contains("foo-bar-baz", 'q')); /// /// assert!(string::contains("foo-bar-baz-foo", "foo")); /// /// assert!( string::contains("foo-bar-baz-foo-bar", "bar")); /// assert!(!string::contains("foo-he-baz-foo-he", "bar")); /// /// ``` /// #[inline] pub const fn contains<'a, P>(left: &str, pat: P) -> bool where P: Pattern<'a>, { let pat = PatternNorm::new(pat); matches!( crate::slice::__bytes_find(left.as_bytes(), pat.as_bytes()), Some(_) ) } /// A const equivalent of /// [`str::rfind`](https://doc.rust-lang.org/std/primitive.str.html#method.rfind) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert_eq!(string::rfind("bar-baz-baz", 'q'), None); /// assert_eq!(string::rfind("bar-baz-baz", '-'), Some(7)); /// /// assert_eq!(string::rfind("bar-baz", "foo"), None); /// assert_eq!(string::rfind("bar-baz-foo", "foo"), Some(8)); /// assert_eq!(string::rfind("foo-bar-baz", "foo"), Some(0)); /// /// ``` /// #[inline] pub const fn rfind<'a, P>(left: &str, pat: P) -> Option where P: Pattern<'a>, { let pat = PatternNorm::new(pat); crate::slice::__bytes_rfind(left.as_bytes(), pat.as_bytes()) } /// A const equivalent of /// [`str::contains`](https://doc.rust-lang.org/std/primitive.str.html#method.contains) /// , taking a [`Pattern`] parameter. /// /// # Example /// /// ```rust /// use konst::string; /// /// assert!(string::rcontains("foo-bar-baz", '-')); /// assert!(!string::rcontains("foo-bar-baz", 'q')); /// /// assert!(!string::rcontains("bar-baz", "foo")); /// assert!(string::rcontains("foo-bar", "foo")); /// /// ``` /// #[inline(always)] pub const fn rcontains<'a, P>(left: &str, pat: P) -> bool where P: Pattern<'a>, { let pat = PatternNorm::new(pat); matches!( crate::slice::__bytes_rfind(left.as_bytes(), pat.as_bytes()), Some(_) ) } /// A const equivalent of `&string[..len]`. /// /// If `string.len() < len`, this simply returns `string` back. /// /// # Panics /// /// This function panics if `len` is inside the string but doesn't fall on a char boundary. /// /// # Example /// /// ``` /// use konst::string::str_up_to; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: &str = str_up_to(STR, 3); /// assert_eq!(SUB0, "foo"); /// /// const SUB1: &str = str_up_to(STR, 7); /// assert_eq!(SUB1, "foo bar"); /// /// const SUB2: &str = str_up_to(STR, 11); /// assert_eq!(SUB2, STR); /// /// const SUB3: &str = str_up_to(STR, 100); /// assert_eq!(SUB3, STR); /// /// /// ``` #[doc(inline)] pub use konst_kernel::string::str_up_to; /// A const equivalent of `&string[start..]`. /// /// If `string.len() < start`, this simply returns an empty string` back. /// /// # Panics /// /// This function panics if `start` is inside the string but doesn't fall on a char boundary. /// /// # Example /// /// ``` /// use konst::string::str_from; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: &str = str_from(STR, 0); /// assert_eq!(SUB0, STR); /// /// const SUB1: &str = str_from(STR, 4); /// assert_eq!(SUB1, "bar baz"); /// /// const SUB2: &str = str_from(STR, 8); /// assert_eq!(SUB2, "baz"); /// /// const SUB3: &str = str_from(STR, 11); /// assert_eq!(SUB3, ""); /// /// const SUB4: &str = str_from(STR, 1000); /// assert_eq!(SUB3, ""); /// /// /// ``` #[doc(inline)] pub use konst_kernel::string::str_from; /// A const equivalent of `&string[start..end]`. /// /// If `start >= end ` or `string.len() < start `, this returns an empty string. /// /// If `string.len() < end`, this returns the string from `start`. /// /// # Alternatives /// /// For a const equivalent of `&string[start..]` there's [`str_from`]. /// /// For a const equivalent of `&string[..end]` there's [`str_up_to`]. /// /// [`str_from`]: ./fn.str_from.html /// [`str_up_to`]: ./fn.str_up_to.html /// /// # Panics /// /// This function panics if either `start` or `end` are inside the string and /// don't fall on a char boundary. /// /// # Example /// /// ``` /// use konst::string::str_range; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: &str = str_range(STR, 0, 3); /// assert_eq!(SUB0, "foo"); /// /// const SUB1: &str = str_range(STR, 0, 7); /// assert_eq!(SUB1, "foo bar"); /// /// const SUB2: &str = str_range(STR, 4, 11); /// assert_eq!(SUB2, "bar baz"); /// /// const SUB3: &str = str_range(STR, 0, 1000); /// assert_eq!(SUB3, STR); /// /// /// ``` #[doc(inline)] pub use konst_kernel::string::str_range; /// Const equivalent of [`str::is_char_boundary`]. /// /// # Example /// /// ``` /// use konst::string::is_char_boundary; /// /// let string = "锈 is 🧠"; /// /// // Start of "锈" /// assert!(is_char_boundary(string, 0)); /// assert!(!is_char_boundary(string, 1)); /// assert!(!is_char_boundary(string, 2)); /// /// // start of " " /// assert!(is_char_boundary(string, 3)); /// /// // start of "🧠" /// assert!(is_char_boundary(string, 7)); /// assert!(!is_char_boundary(string, 8)); /// /// // end of string /// assert!(is_char_boundary(string, string.len())); /// /// // after end of string /// assert!(!is_char_boundary(string, string.len() + 1)); /// /// /// ``` #[doc(inline)] pub use konst_kernel::string::is_char_boundary; /// Checks that the start and end are valid utf8 char boundaries /// when the `"debug"` feature is enabled. /// /// When the `"debug"` feature is disabled, /// this is equivalent to calling `core::str::from_utf8_unchecled` /// /// # Safety /// /// The input byte slice must be a subslice of a `&str`, /// so that only the start and end need to be checked. #[doc(inline)] pub use konst_kernel::string::__from_u8_subslice_of_str; /// A const equivalent of `string.get(..len)`. /// /// # Example /// /// ``` /// use konst::string; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: Option<&str> = string::get_up_to(STR, 3); /// assert_eq!(SUB0, Some("foo")); /// /// const SUB1: Option<&str> = string::get_up_to(STR, 7); /// assert_eq!(SUB1, Some("foo bar")); /// /// const SUB2: Option<&str> = string::get_up_to(STR, 11); /// assert_eq!(SUB2, Some(STR)); /// /// const SUB3: Option<&str> = string::get_up_to(STR, 100); /// assert_eq!(SUB3, None); /// /// /// ``` pub const fn get_up_to(string: &str, len: usize) -> Option<&str> { let bytes = string.as_bytes(); crate::option::and_then!( crate::slice::get_up_to(bytes, len), |x| if __is_char_boundary_bytes(bytes, len) { // Safety: __is_char_boundary_bytes checks that `len` falls on a char boundary. unsafe { Some(__from_u8_subslice_of_str(x)) } } else { None } ) } /// A const equivalent of `string.get(from..)`. /// /// # Example /// /// ``` /// use konst::string; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: Option<&str> = string::get_from(STR, 0); /// assert_eq!(SUB0, Some(STR)); /// /// const SUB1: Option<&str> = string::get_from(STR, 4); /// assert_eq!(SUB1, Some("bar baz")); /// /// const SUB2: Option<&str> = string::get_from(STR, 8); /// assert_eq!(SUB2, Some("baz")); /// /// const SUB3: Option<&str> = string::get_from(STR, 100); /// assert_eq!(SUB3, None); /// /// /// ``` pub const fn get_from(string: &str, from: usize) -> Option<&str> { let bytes = string.as_bytes(); crate::option::and_then!( crate::slice::get_from(bytes, from), |x| if __is_char_boundary_bytes(bytes, from) { // Safety: __is_char_boundary_bytes checks that `from` falls on a char boundary. unsafe { Some(__from_u8_subslice_of_str(x)) } } else { None } ) } /// A const equivalent of [`str::split_at`] /// /// If `at > string.len()` this returns `(string, "")`. /// /// # Panics /// /// This function panics if `at` is inside the string but doesn't fall on a char boundary. /// /// # Example /// /// ```rust /// use konst::string; /// /// const IN: &str = "foo bar baz"; /// /// { /// const SPLIT0: (&str, &str) = string::split_at(IN, 0); /// assert_eq!(SPLIT0, ("", "foo bar baz")); /// } /// { /// const SPLIT1: (&str, &str) = string::split_at(IN, 4); /// assert_eq!(SPLIT1, ("foo ", "bar baz")); /// } /// { /// const SPLIT2: (&str, &str) = string::split_at(IN, 8); /// assert_eq!(SPLIT2, ("foo bar ", "baz")); /// } /// { /// const SPLIT3: (&str, &str) = string::split_at(IN, 11); /// assert_eq!(SPLIT3, ("foo bar baz", "")); /// } /// { /// const SPLIT4: (&str, &str) = string::split_at(IN, 13); /// assert_eq!(SPLIT4, ("foo bar baz", "")); /// } /// /// ``` /// /// [`str::split_at`]: https://doc.rust-lang.org/std/primitive.str.html#method.split_at pub const fn split_at(string: &str, at: usize) -> (&str, &str) { (str_up_to(string, at), str_from(string, at)) } /// A const equivalent of `string.get(start..end)`. /// /// # Alternatives /// /// For a const equivalent of `string.get(start..)` there's [`get_from`]. /// /// For a const equivalent of `string.get(..end)` there's [`get_up_to`]. /// /// [`get_from`]: ./fn.get_from.html /// [`get_up_to`]: ./fn.get_up_to.html /// /// # Example /// /// ``` /// use konst::string; /// /// const STR: &str = "foo bar baz"; /// /// const SUB0: Option<&str> = string::get_range(STR, 0, 3); /// assert_eq!(SUB0, Some("foo")); /// /// const SUB1: Option<&str> = string::get_range(STR, 0, 7); /// assert_eq!(SUB1, Some("foo bar")); /// /// const SUB2: Option<&str> = string::get_range(STR, 4, 11); /// assert_eq!(SUB2, Some("bar baz")); /// /// const SUB3: Option<&str> = string::get_range(STR, 0, 1000); /// assert_eq!(SUB3, None); /// /// /// ``` pub const fn get_range(string: &str, start: usize, end: usize) -> Option<&str> { let bytes = string.as_bytes(); crate::option::and_then!(crate::slice::get_range(bytes, start, end), |x| { if __is_char_boundary_bytes(bytes, start) && __is_char_boundary_bytes(bytes, end) { // Safety: __is_char_boundary_bytes checks that `start` and `end` fall on a char boundary. unsafe { Some(__from_u8_subslice_of_str(x)) } } else { None } }) } /// A const subset of [`str::strip_prefix`]. /// /// This takes [`Pattern`] implementors as the pattern. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const STRIP: Option<&str> = string::strip_prefix("--5 8", '-'); /// assert_eq!(STRIP, Some("-5 8")); /// } /// { /// const STRIP: Option<&str> = string::strip_prefix("--5 8", '_'); /// assert_eq!(STRIP, None); /// } /// /// { /// const STRIP: Option<&str> = string::strip_prefix("33 5 8", "3"); /// assert_eq!(STRIP, Some("3 5 8")); /// } /// { /// const STRIP: Option<&str> = string::strip_prefix("3 5 8", "hello"); /// assert_eq!(STRIP, None); /// } /// /// /// ``` /// /// [`str::strip_prefix`]: https://doc.rust-lang.org/std/primitive.str.html#method.strip_prefix pub const fn strip_prefix<'a, 'p, P>(string: &'a str, pattern: P) -> Option<&'a str> where P: Pattern<'p>, { let pat = PatternNorm::new(pattern); // Safety: because `pat` is a `Pattern`, removing it should result in a valid `&str` unsafe { crate::option::map!( crate::slice::__bytes_strip_prefix(string.as_bytes(), pat.as_bytes()), __from_u8_subslice_of_str, ) } } /// A const subset of [`str::strip_suffix`]. /// /// This takes [`Pattern`] implementors as the pattern. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const STRIP: Option<&str> = string::strip_suffix("3 5 8--", '-'); /// assert_eq!(STRIP, Some("3 5 8-")); /// } /// { /// const STRIP: Option<&str> = string::strip_suffix("3 5 8", '_'); /// assert_eq!(STRIP, None); /// } /// /// { /// const STRIP: Option<&str> = string::strip_suffix("3 5 6868", "68"); /// assert_eq!(STRIP, Some("3 5 68")); /// } /// { /// const STRIP: Option<&str> = string::strip_suffix("3 5 8", "hello"); /// assert_eq!(STRIP, None); /// } /// /// /// ``` /// pub const fn strip_suffix<'a, 'p, P>(string: &'a str, pattern: P) -> Option<&'a str> where P: Pattern<'p>, { let pat = PatternNorm::new(pattern); // Safety: because `suffix` is a `&str`, removing it should result in a valid `&str` unsafe { crate::option::map!( crate::slice::__bytes_strip_suffix(string.as_bytes(), pat.as_bytes()), __from_u8_subslice_of_str, ) } } /// A const subset of [`str::trim`] which only removes ascii whitespace. /// /// # Const stabilization /// /// The [equivalent std function](str::trim_ascii) was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::string; /// /// const TRIMMED: &str = string::trim("\nhello world "); /// /// assert_eq!(TRIMMED, "hello world"); /// /// ``` pub const fn trim(this: &str) -> &str { let trimmed = crate::slice::bytes_trim(this.as_bytes()); // safety: bytes_trim only removes ascii bytes unsafe { __from_u8_subslice_of_str(trimmed) } } /// A const subset of [`str::trim_start`] which only removes ascii whitespace. /// /// # Const stabilization /// /// The [equivalent std function](str::trim_ascii_start) was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::string; /// /// const TRIMMED: &str = string::trim_start("\rfoo bar "); /// /// assert_eq!(TRIMMED, "foo bar "); /// /// ``` pub const fn trim_start(this: &str) -> &str { let trimmed = crate::slice::bytes_trim_start(this.as_bytes()); // safety: bytes_trim_start only removes ascii bytes unsafe { __from_u8_subslice_of_str(trimmed) } } /// A const subset of [`str::trim_end`] which only removes ascii whitespace. /// /// # Const stabilization /// /// The [equivalent std function](str::trim_ascii_end) was const-stabilized in Rust 1.80.0. /// /// # Example /// /// ```rust /// use konst::string; /// /// const TRIMMED: &str = string::trim_end("\rfoo bar "); /// /// assert_eq!(TRIMMED, "\rfoo bar"); /// /// ``` /// pub const fn trim_end(this: &str) -> &str { let trimmed = crate::slice::bytes_trim_end(this.as_bytes()); // safety: bytes_trim_end only removes ascii bytes unsafe { __from_u8_subslice_of_str(trimmed) } } /// A const subset of [`str::trim_matches`]. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// const CHAR_TRIMMED: &str = string::trim_matches("---baz qux---", '-'); /// const STR_TRIMMED: &str = string::trim_matches("<>baz qux<><><>", "<>"); /// /// assert_eq!(CHAR_TRIMMED, "baz qux"); /// assert_eq!(STR_TRIMMED, "baz qux"); /// /// ``` pub const fn trim_matches<'a, 'p, P>(this: &'a str, needle: P) -> &'a str where P: Pattern<'p>, { let needle = PatternNorm::new(needle); let trimmed = crate::slice::__bytes_trim_matches(this.as_bytes(), needle.as_bytes()); // safety: // because bytes_trim_matches was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. unsafe { __from_u8_subslice_of_str(trimmed) } } /// A const subset of [`str::trim_start_matches`]. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// const CHAR_TRIMMED: &str = string::trim_start_matches("#####huh###", '#'); /// const STR_TRIMMED: &str = string::trim_start_matches("#####huh###", "##"); /// /// assert_eq!(CHAR_TRIMMED, "huh###"); /// assert_eq!(STR_TRIMMED, "#huh###"); /// /// ``` pub const fn trim_start_matches<'a, 'p, P>(this: &'a str, needle: P) -> &'a str where P: Pattern<'p>, { let needle = PatternNorm::new(needle); let trimmed = crate::slice::__bytes_trim_start_matches(this.as_bytes(), needle.as_bytes()); // safety: // because bytes_trim_start_matches was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. unsafe { __from_u8_subslice_of_str(trimmed) } } /// A const subset of [`str::trim_end_matches`]. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// const CHAR_TRIMMED: &str = string::trim_end_matches("oowowooooo", 'o'); /// const STR_TRIMMED: &str = string::trim_end_matches("oowowooooo", "oo"); /// /// assert_eq!(CHAR_TRIMMED, "oowow"); /// assert_eq!(STR_TRIMMED, "oowowo"); /// /// ``` pub const fn trim_end_matches<'a, 'p, P>(this: &'a str, needle: P) -> &'a str where P: Pattern<'p>, { let needle = PatternNorm::new(needle); let trimmed = crate::slice::__bytes_trim_end_matches(this.as_bytes(), needle.as_bytes()); // safety: // because bytes_trim_end_matches was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. unsafe { __from_u8_subslice_of_str(trimmed) } } /// Advances `this` past the first instance of `needle`. /// /// Returns `None` if no instance of `needle` is found. /// /// Returns `Some(this)` if `needle` is empty. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const FOUND: Option<&str> = string::find_skip("foo bar baz", ' '); /// assert_eq!(FOUND, Some("bar baz")); /// } /// /// { /// const FOUND: Option<&str> = string::find_skip("foo bar baz", "bar"); /// assert_eq!(FOUND, Some(" baz")); /// } /// { /// const NOT_FOUND: Option<&str> = string::find_skip("foo bar baz", "qux"); /// assert_eq!(NOT_FOUND, None); /// } /// ``` pub const fn find_skip<'a, 'p, P>(this: &'a str, needle: P) -> Option<&'a str> where P: Pattern<'p>, { let needle = PatternNorm::new(needle); unsafe { crate::option::map!( crate::slice::__bytes_find_skip(this.as_bytes(), needle.as_bytes()), // safety: // because bytes_find_skip was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. __from_u8_subslice_of_str, ) } } /// Advances `this` up to the first instance of `needle`. /// /// Returns `None` if no instance of `needle` is found. /// /// Returns `Some(this)` if `needle` is empty. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const FOUND: Option<&str> = string::find_keep("foo-bar-baz", '-'); /// assert_eq!(FOUND, Some("-bar-baz")); /// } /// /// { /// const FOUND: Option<&str> = string::find_keep("foo bar baz", "bar"); /// assert_eq!(FOUND, Some("bar baz")); /// } /// { /// const NOT_FOUND: Option<&str> = string::find_keep("foo bar baz", "qux"); /// assert_eq!(NOT_FOUND, None); /// } /// ``` pub const fn find_keep<'a, 'p, P>(this: &'a str, needle: P) -> Option<&'a str> where P: Pattern<'p>, { let needle = PatternNorm::new(needle); unsafe { crate::option::map!( crate::slice::__bytes_find_keep(this.as_bytes(), needle.as_bytes()), // safety: // because bytes_find_keep was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. __from_u8_subslice_of_str, ) } } /// Truncates `this` to before the last instance of `needle`. /// /// Returns `None` if no instance of `needle` is found. /// /// Returns `Some(this)` if `needle` is empty. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const FOUND: Option<&str> = string::rfind_skip("foo bar _ bar baz", '_'); /// assert_eq!(FOUND, Some("foo bar ")); /// } /// /// { /// const FOUND: Option<&str> = string::rfind_skip("foo bar _ bar baz", "bar"); /// assert_eq!(FOUND, Some("foo bar _ ")); /// } /// { /// const NOT_FOUND: Option<&str> = string::rfind_skip("foo bar baz", "qux"); /// assert_eq!(NOT_FOUND, None); /// } /// ``` pub const fn rfind_skip<'a, 'p, P>(this: &'a str, needle: P) -> Option<&'a str> where P: Pattern<'p>, { let needle = PatternNorm::new(needle); unsafe { crate::option::map!( crate::slice::__bytes_rfind_skip(this.as_bytes(), needle.as_bytes()), // safety: // because bytes_rfind_skip was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. __from_u8_subslice_of_str, ) } } /// Truncates `this` to the last instance of `needle`. /// /// Returns `None` if no instance of `needle` is found. /// /// Returns `Some(this)` if `needle` is empty. /// /// This takes [`Pattern`] implementors as the needle. /// /// # Example /// /// ```rust /// use konst::string; /// /// { /// const FOUND: Option<&str> = string::rfind_keep("foo bar _ bar baz", '_'); /// assert_eq!(FOUND, Some("foo bar _")); /// } /// /// { /// const FOUND: Option<&str> = string::rfind_keep("foo bar _ bar baz", "bar"); /// assert_eq!(FOUND, Some("foo bar _ bar")); /// } /// { /// const NOT_FOUND: Option<&str> = string::rfind_keep("foo bar baz", "qux"); /// assert_eq!(NOT_FOUND, None); /// } /// ``` pub const fn rfind_keep<'a, 'p, P>(this: &'a str, needle: P) -> Option<&'a str> where P: Pattern<'p>, { let needle = PatternNorm::new(needle); unsafe { crate::option::map!( crate::slice::__bytes_rfind_keep(this.as_bytes(), needle.as_bytes()), // safety: // because bytes_rfind_keep was passed `&str`s casted to `&[u8]`s, // it returns a valid utf8 sequence. __from_u8_subslice_of_str, ) } } konst-0.3.16/src/utils.rs000064400000000000000000000000011046102023000133350ustar 00000000000000