konst/lib.rs
1//! Const equivalents of std functions and const parsing.
2//!
3//! # Features
4//!
5//! This crate provides:
6//!
7//! - Const fn equivalents of standard library functions and methods.
8//!
9//! - [`destructure`] macro to allow destructuring types in const without getting "cannot drop in const" errors.
10//!
11//! - Compile-time parsing through the [`Parser`] type, and [`parser_method`] macro.
12//!
13//! # Examples
14//!
15//! ### Parsing an enum
16//!
17//! This example demonstrates how you can parse a simple enum from an environment variable,
18//! at compile-time.
19//!
20//! ```rust
21//! use konst::{
22//! eq_str,
23//! option,
24//! result::unwrap_ctx,
25//! };
26//!
27//! #[derive(Debug, PartialEq)]
28//! enum Direction {
29//! Forward,
30//! Backward,
31//! Left,
32//! Right,
33//! }
34//!
35//! impl Direction {
36//! const fn try_parse(input: &str) -> Result<Self, ParseDirectionError> {
37//! // As of Rust 1.65.0, string patterns don't work in const contexts
38//! match () {
39//! _ if eq_str(input, "forward") => Ok(Direction::Forward),
40//! _ if eq_str(input, "backward") => Ok(Direction::Backward),
41//! _ if eq_str(input, "left") => Ok(Direction::Left),
42//! _ if eq_str(input, "right") => Ok(Direction::Right),
43//! _ => Err(ParseDirectionError),
44//! }
45//! }
46//! }
47//!
48//! const CHOICE: &str = option::unwrap_or!(option_env!("chosen-direction"), "forward");
49//!
50//! const DIRECTION: Direction = unwrap_ctx!(Direction::try_parse(CHOICE));
51//!
52//! fn main() {
53//! match DIRECTION {
54//! Direction::Forward => assert_eq!(CHOICE, "forward"),
55//! Direction::Backward => assert_eq!(CHOICE, "backward"),
56//! Direction::Left => assert_eq!(CHOICE, "left"),
57//! Direction::Right => assert_eq!(CHOICE, "right"),
58//! }
59//! }
60//!
61//! #[derive(Debug, PartialEq)]
62//! pub struct ParseDirectionError;
63//!
64//! use std::fmt::{self, Display};
65//!
66//! impl Display for ParseDirectionError {
67//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68//! f.write_str("Failed to parse a Direction")
69//! }
70//! }
71//!
72//! impl ParseDirectionError {
73//! const fn panic(&self) -> ! {
74//! panic!("failed to parse a Direction")
75//! }
76//! }
77//!
78//! ```
79//!
80//! ### Parsing CSV
81//!
82//! This example demonstrates how CSV can be parsed into integers.
83//!
84//! This example requires the `"parsing"` and `"iter"` features
85//! (both are enabled by default).
86//!
87#![cfg_attr(all(feature = "parsing", feature = "iter"), doc = "```rust")]
88#![cfg_attr(not(all(feature = "parsing", feature = "iter")), doc = "```ignore")]
89//! use konst::{
90//! primitive::parse_u64,
91//! result::unwrap_ctx,
92//! iter, string,
93//! };
94//!
95//! const CSV: &str = "3, 8, 13, 21, 34";
96//!
97//! static PARSED: [u64; 5] = iter::collect_const!(u64 =>
98//! string::split(CSV, ","),
99//! map(string::trim),
100//! map(|s| unwrap_ctx!(parse_u64(s))),
101//! );
102//!
103//! assert_eq!(PARSED, [3, 8, 13, 21, 34]);
104//!
105//! ```
106//!
107//! ### Parsing a struct
108//!
109//! This example demonstrates how a key-value pair format can be parsed into a struct.
110//!
111//! This requires the `"parsing_proc"` feature (enabled by default).
112//!
113#![cfg_attr(feature = "parsing_proc", doc = "```rust")]
114#![cfg_attr(not(feature = "parsing_proc"), doc = "```ignore")]
115//! use konst::{
116//! parsing::{Parser, ParseValueResult},
117//! eq_str,
118//! for_range, parser_method, try_, unwrap_ctx,
119//! };
120//!
121//! const PARSED: Struct = {
122//! // You can also parse strings from environment variables, or from an `include_str!(....)`
123//! let input = "\
124//! colors = red, blue, green, blue
125//! amount = 1000
126//! repeating = circle
127//! name = bob smith
128//! ";
129//!
130//! unwrap_ctx!(parse_struct(Parser::new(input))).0
131//! };
132//!
133//! fn main(){
134//! assert_eq!(
135//! PARSED,
136//! Struct{
137//! name: "bob smith",
138//! amount: 1000,
139//! repeating: Shape::Circle,
140//! colors: [Color::Red, Color::Blue, Color::Green, Color::Blue],
141//! }
142//! );
143//! }
144//!
145//! #[derive(Debug, Clone, PartialEq, Eq)]
146//! pub struct Struct<'a> {
147//! pub name: &'a str,
148//! pub amount: usize,
149//! pub repeating: Shape,
150//! pub colors: [Color; 4],
151//! }
152//!
153//! #[derive(Debug, Clone, PartialEq, Eq)]
154//! pub enum Shape {
155//! Circle,
156//! Square,
157//! Line,
158//! }
159//!
160//! #[derive(Debug, Copy, Clone, PartialEq, Eq)]
161//! pub enum Color {
162//! Red,
163//! Blue,
164//! Green,
165//! }
166//!
167//! pub const fn parse_struct(mut parser: Parser<'_>) -> ParseValueResult<'_, Struct<'_>> {
168//! let mut name = "<none>";
169//! let mut amount = 0;
170//! let mut repeating = Shape::Circle;
171//! let mut colors = [Color::Red; 4];
172//!
173//! parser = parser.trim_end();
174//! if !parser.is_empty() {
175//! loop {
176//! let mut prev_parser = parser.trim_start();
177//!
178//! parser = try_!(parser.find_skip('='));
179//!
180//! parser_method!{prev_parser, strip_prefix;
181//! "name" => (name, parser) = try_!(parser.trim_start().split_keep('\n')),
182//! "amount" => (amount, parser) = try_!(parser.trim_start().parse_usize()),
183//! "repeating" => (repeating, parser) = try_!(parse_shape(parser.trim_start())),
184//! "colors" => (colors, parser) = try_!(parse_colors(parser.trim_start())),
185//! _ => {
186//! let err = &"could not parse Struct field name";
187//! return Err(prev_parser.into_other_error(err));
188//! }
189//! }
190//!
191//! if parser.is_empty() {
192//! break
193//! }
194//! parser = try_!(parser.strip_prefix("\n"));
195//! }
196//! }
197//!
198//! Ok((Struct{name, amount, repeating, colors}, parser))
199//! }
200//!
201//! pub const fn parse_shape(mut parser: Parser<'_>) -> ParseValueResult<'_, Shape> {
202//! let shape = parser_method!{parser, strip_prefix;
203//! "circle" => Shape::Circle,
204//! "square" => Shape::Square,
205//! "line" => Shape::Line,
206//! _ => return Err(parser.into_other_error(&"could not parse Shape"))
207//! };
208//! Ok((shape, parser))
209//! }
210//!
211//! pub const fn parse_colors<const LEN: usize>(
212//! mut parser: Parser<'_>,
213//! ) -> ParseValueResult<'_, [Color; LEN]> {
214//! let mut colors = [Color::Red; LEN];
215//!
216//! for_range!{i in 0..LEN =>
217//! (colors[i], parser) = try_!(parse_color(parser.trim_start()));
218//!
219//! match parser.strip_prefix(",") {
220//! Ok(next) => parser = next,
221//! Err(_) if i == LEN - 1 => {}
222//! Err(e) => return Err(e),
223//! }
224//! }
225//!
226//! Ok((colors, parser))
227//! }
228//!
229//! pub const fn parse_color(mut parser: Parser<'_>) -> ParseValueResult<'_, Color> {
230//! let color = parser_method!{parser, strip_prefix;
231//! "red" => Color::Red,
232//! "blue" => Color::Blue,
233//! "green" => Color::Green,
234//! _ => return Err(parser.into_other_error(&"could not parse Color"))
235//! };
236//! Ok((color, parser))
237//! }
238//!
239//!
240//!
241//! ```
242//!
243//! # Cargo features
244//!
245//! These are the features of these crates:
246//!
247//! - `"iter"`(enabled by default):
248//! Enables all iteration items, including macros/functions that take/return iterators,
249//!
250//! - `"cmp"`(enabled by default):
251//! Enables all comparison functions and macros,
252//! the string equality and ordering comparison functions don't require this feature.
253//!
254//! - `"parsing_proc"`(enabled by default):
255//! Enables the `"parsing"` feature, compiles the `konst_proc_macros` dependency,
256//! and enables the [`parser_method`] macro.
257//! You can use this feature instead of `"parsing"` if the slightly longer
258//! compile times aren't a problem.
259//!
260//! - `"parsing"`(enabled by default):
261//! Enables the [`parsing`] module (for parsing from `&str` and `&[u8]`),
262//! the `primitive::parse_*` functions, `try_rebind`, and `rebind_if_ok` macros.
263//!
264//! - `"alloc"`:
265//! Enables items that use types from the [`alloc`] crate, including `Vec` and `String`.
266//!
267//! ### Rust release related
268//!
269//! None of thse features are enabled by default.
270//!
271//! - `"rust_latest_stable"`: enables the latest `"rust_1_*"` feature.
272//! Only recommendable if you can update the Rust compiler every stable release.
273//!
274//! - `"rust_1_83"`:
275//! Enables const functions that take mutable references,
276//! `array::{from_fn_, map_}` macros, and [`destructure`] macro.
277//!
278//! # No-std support
279//!
280//! `konst` is `#![no_std]`, it can be used anywhere Rust can be used.
281//!
282//! # Minimum Supported Rust Version
283//!
284//! `konst` requires Rust 1.65.0.
285//!
286//! Features that require newer versions of Rust, or the nightly compiler,
287//! need to be explicitly enabled with crate features.
288//!
289//!
290//!
291//! [`alloc`]: https://doc.rust-lang.org/alloc/
292//! [`const_eq`]: ./macro.const_eq.html
293//! [`const_eq_for`]: ./macro.const_eq_for.html
294//! [`const_cmp`]: ./macro.const_cmp.html
295//! [`const_cmp_for`]: ./macro.const_cmp_for.html
296//! [`parsing`]: ./parsing/index.html
297//! [`primitive`]: ./primitive/index.html
298//! [`parser_method`]: macro.parser_method.html
299//! [`Parser`]: ./parsing/struct.Parser.html
300//! [`Parser::parse_u128`]: ./parsing/struct.Parser.html#method.parse_u128
301//! [`destructure`]: ./macro.destructure.html
302//!
303#![deny(missing_docs)]
304#![deny(unused_results)]
305#![allow(rustdoc::redundant_explicit_links)]
306// clippy's opinionated BS
307#![allow(clippy::needless_doctest_main)]
308#![allow(clippy::init_numbered_fields)]
309////////////
310#![forbid(clippy::missing_const_for_fn)]
311#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
312#![no_std]
313
314#[cfg(feature = "alloc")]
315extern crate alloc;
316
317include! {"./root_module_macros.rs"}
318
319#[macro_use]
320#[doc(hidden)]
321pub mod macros;
322
323#[doc(hidden)]
324pub mod __for_cmp_impls;
325
326// pub mod other;
327
328#[cfg(feature = "alloc")]
329#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
330pub mod alloc_type;
331
332pub mod array;
333
334pub mod chr;
335
336#[cfg(feature = "cmp")]
337#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))]
338pub mod cmp;
339
340#[cfg(feature = "iter")]
341#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
342pub mod iter;
343
344/// const equivalents of `core::ffi` functions
345pub mod ffi;
346
347pub mod polymorphism;
348
349pub mod primitive;
350
351pub mod option;
352
353pub mod result;
354
355pub mod range;
356
357pub mod maybe_uninit;
358
359pub mod manually_drop;
360
361pub mod nonzero;
362
363pub mod other;
364
365#[cfg(feature = "parsing")]
366#[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))]
367pub mod parsing;
368
369pub mod ptr;
370
371mod utils;
372
373#[allow(unused_imports)]
374mod utils_1_56 {
375 pub(crate) use konst_kernel::__priv_transmute;
376}
377
378#[cfg(feature = "parsing")]
379#[cfg_attr(feature = "docsrs", doc(cfg(feature = "parsing")))]
380pub use crate::parsing::Parser;
381
382#[cfg(feature = "parsing_proc")]
383#[doc(hidden)]
384pub use konst_proc_macros::{__priv_bstr_end, __priv_bstr_start};
385
386pub mod slice;
387
388pub mod string;
389
390pub use ::const_panic;
391
392pub use crate::string::{cmp_str, eq_str};
393
394#[doc(no_inline)]
395pub use crate::result::unwrap_ctx;
396
397#[cfg(feature = "cmp")]
398#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))]
399pub use crate::string::{cmp_option_str, eq_option_str};
400
401#[cfg(all(doctest, feature = "iter", feature = "parsing_proc"))]
402#[doc = include_str!("../../README.md")]
403pub struct ReadmeTest;
404
405#[doc(hidden)]
406pub mod __ {
407 pub use core::{
408 cmp::Ordering::{self, Equal, Greater, Less},
409 compile_error,
410 marker::PhantomData,
411 matches,
412 mem::{self, ManuallyDrop},
413 ops::Range,
414 option::Option::{self, None, Some},
415 primitive::usize,
416 ptr,
417 result::Result::{self, Err, Ok},
418 };
419
420 pub mod v {
421 pub use core::{
422 option::Option::Some,
423 result::Result::{Err, Ok},
424 };
425 }
426
427 pub use crate::__for_cmp_impls::U8Ordering;
428
429 pub use konst_kernel::utils::{__parse_closure_1, __parse_closure_2};
430 pub use konst_kernel::__::unit_array;
431 pub use konst_kernel::{__priv_transmute, __split_array_type_and_closure, __unparenthesize_ty};
432
433 #[cfg(feature = "cmp")]
434 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))]
435 pub use crate::cmp::{CmpWrapper, ConstCmp, IsAConstCmp, IsNotStdKind, IsStdKind};
436
437 pub use const_panic::concat_panic;
438}