rng_query/
lib.rs

1//! Small query language for pseudorandomness
2//!
3//! See <https://github.com/Zheoni/rng-query> for the syntax and CLI.
4//!
5//! ## Usage as a lib
6//!
7//! `rng-query` is mainly the CLI app, so this lib is not the main objective. I
8//! will try to follow [semver](https://semver.org/) but for the lib it's not a
9//! guarantee, so you may want to pin a specific version.
10//!
11//! Run a whole input with [`run_query`] or have more control with [`State`] and
12//! its methods.
13//!
14//! All [`Display`](std::fmt::Display) implementations of the crate *may* output ANSI color codes.
15//! Use something like [anstream](https://docs.rs/anstream/) if you dont want
16//! colors.
17
18mod ast;
19mod eval;
20mod expr;
21mod parse;
22
23use ast::Entry;
24use eval::Eval;
25pub use eval::Sample;
26use parse::parse_query;
27use rand::SeedableRng;
28use rand_pcg::Pcg64 as Pcg;
29
30macro_rules! regex {
31    ($re:literal $(,)?) => {{
32        static RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
33        RE.get_or_init(|| regex::Regex::new($re).unwrap())
34    }};
35}
36pub(crate) use regex;
37
38/// Run a query
39pub fn run_query(input: &str) -> Result<Vec<Sample>, Error> {
40    let mut state = State::new();
41    state.run_query(input)
42}
43
44/// Query interpreter
45#[derive(Debug, Clone)]
46pub struct State {
47    rng: Pcg,
48    data: Vec<(usize, Entry)>,
49}
50
51impl State {
52    /// Create a new state
53    ///
54    /// Seed is autogenerated form entropy.
55    pub fn new() -> Self {
56        Self::from_rng(Pcg::from_entropy())
57    }
58    /// Create a new state with a seed
59    pub fn with_seed(seed: u64) -> Self {
60        Self::from_rng(Pcg::seed_from_u64(seed))
61    }
62    fn from_rng(rng: Pcg) -> Self {
63        Self {
64            rng,
65            data: Vec::new(),
66        }
67    }
68}
69
70impl Default for State {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76impl State {
77    /// Runs a query
78    ///
79    /// It will consume entries from the state if any.
80    pub fn run_query(&mut self, input: &str) -> Result<Vec<Sample>, Error> {
81        let mut ast = parse_query(input)?;
82        if !self.data.is_empty() {
83            let mut entries = std::mem::take(&mut self.data);
84            let last_id = entries.last().map(|(id, _)| *id).unwrap_or(0);
85
86            entries.reserve(ast.root.entries.len());
87            for (id, e) in ast.root.entries {
88                entries.push((id + last_id + 1, e));
89            }
90            debug_assert!(entries.windows(2).all(|w| w[0].0 + 1 == w[1].0));
91            ast.root.entries = entries;
92        }
93        let res = ast.eval(&mut self.rng);
94        let v = match res {
95            eval::EvalRes::Emtpy => vec![],
96            eval::EvalRes::Single(s) => vec![s],
97            eval::EvalRes::Many(v) => v,
98        };
99        Ok(v)
100    }
101
102    fn push_entry(&mut self, entry: Entry) {
103        let id = self.data.len();
104        self.data.push((id, entry));
105    }
106
107    /// Adds data entries for the next query
108    pub fn add_data(&mut self, entry: &str) {
109        self.push_entry(Entry::data(entry.trim()));
110    }
111
112    /// Adds a regular entry for the next query
113    pub fn add_entry(&mut self, entry: &str) -> Result<(), Error> {
114        let entry = Entry::parse(entry.trim())?;
115        self.push_entry(entry);
116        Ok(())
117    }
118}
119
120/// Query error
121#[derive(Debug)]
122pub enum Error {
123    /// Parsing options
124    Options(String),
125    /// Parsing expressions
126    Expr(String),
127    /// Query structure error
128    ParseQuery(String),
129}
130
131impl std::fmt::Display for Error {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        match self {
134            Error::Options(e) => write!(f, "options: {e}"),
135            Error::Expr(e) => write!(f, "expresions: {e}"),
136            Error::ParseQuery(e) => write!(f, "query structure: {e}"),
137        }
138    }
139}
140
141impl std::error::Error for Error {}