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}