#const-fn #parser #no-std

no-std konst

std 函数的常量等效、编译时比较和解析

32 个版本

0.3.9 2024年4月17日
0.3.8 2023年12月6日
0.3.7 2023年11月28日
0.3.5 2023年5月1日
0.2.4 2021年3月31日

Rust 模式 中排名第 72

Download history 27193/week @ 2024-04-30 29106/week @ 2024-05-07 35670/week @ 2024-05-14 38046/week @ 2024-05-21 50697/week @ 2024-05-28 50955/week @ 2024-06-04 41536/week @ 2024-06-11 34574/week @ 2024-06-18 33555/week @ 2024-06-25 30235/week @ 2024-07-02 57198/week @ 2024-07-09 75762/week @ 2024-07-16 57961/week @ 2024-07-23 84045/week @ 2024-07-30 63018/week @ 2024-08-06 67862/week @ 2024-08-13

每月下载量 289,035
89 个crate中使用 (15 个直接使用)

许可证:Zlib

545KB
9K SLoC

Rust crates-io api-docs

std 函数的常量等效和常量解析。

功能

本crate提供

  • 标准库函数和方法的常量等效。

  • 通过 Parser 类型,以及 parser_method 宏进行编译时解析。

示例

解析枚举

本示例演示了如何在编译时从环境变量中解析一个简单的枚举。

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<Self, ParseDirectionError> {
        // 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")
    }
}

解析 CSV

本示例演示了如何将 CSV 解析为整数。

此示例需要 "parsing""iter" 功能(两者都默认启用)。

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" 功能(默认启用)。

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 = "<none>";
    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<const LEN: usize>(
    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 功能

以下为这些crate的功能

  • "iter"(默认启用):启用所有迭代项,包括接受/返回迭代器的宏/函数,

  • "cmp"(默认启用):启用所有比较函数和宏,字符串相等性和排序比较函数不需要此功能。

  • "parsing_proc"(默认启用):启用 "parsing" 功能,编译 konst_proc_macros 依赖项,并启用 parser_method 宏。如果编译时间稍长不是问题,可以使用此功能代替 "parsing"

  • "parsing"(默认启用):启用 parsing 模块(用于从 &str&[u8] 解析),primitive::parse_* 函数,以及 try_rebindrebind_if_ok 宏。

  • alloc":启用使用 alloc crate 中的类型的项,包括 VecString

默认情况下,所有这些功能都没有启用。

  • "rust_latest_stable":启用最新的 "rust_1_*" 功能(目前没有)。只有当你能够每发布一个稳定版本的 Rust 编译器时才推荐使用。

  • "mut_refs"(默认禁用):启用接受可变引用的常量函数。在可变引用在常量上下文中稳定时使用此功能。还启用 "rust_latest_stable" 功能。

  • "nightly_mut_refs"(默认禁用):启用 "mut_refs" 功能。需要 Rust 夜间版本。

No-std 支持

konst#![no_std],可以在任何可以使用 Rust 的地方使用。

最低支持的 Rust 版本

konst 需要 Rust 1.65.0。

需要较新版本的 Rust 或夜间编译器的功能需要通过 crate 功能显式启用。

依赖项

~0.5–8MB
~54K SLoC