Skip to main content

cognis_core/output_parsers/
boolean.rs

1//! Boolean parser — yes/no, true/false, 1/0.
2
3use async_trait::async_trait;
4
5use crate::output_parsers::OutputParser;
6use crate::runnable::{Runnable, RunnableConfig};
7use crate::{CognisError, Result};
8
9/// Parses common yes/no representations into `bool`. Case-insensitive,
10/// whitespace tolerant. Anything else errors with
11/// `CognisError::Serialization`.
12#[derive(Debug, Default, Clone, Copy)]
13pub struct BooleanParser;
14
15impl BooleanParser {
16    /// Construct a `BooleanParser`.
17    pub fn new() -> Self {
18        Self
19    }
20}
21
22impl OutputParser<bool> for BooleanParser {
23    fn parse(&self, text: &str) -> Result<bool> {
24        let t = text.trim().to_lowercase();
25        match t.as_str() {
26            "yes" | "true" | "y" | "1" => Ok(true),
27            "no" | "false" | "n" | "0" => Ok(false),
28            other => Err(CognisError::Serialization(format!(
29                "BooleanParser: cannot parse `{other}` as bool"
30            ))),
31        }
32    }
33    fn format_instructions(&self) -> Option<String> {
34        Some("Reply with exactly one word: `yes` or `no`.".into())
35    }
36}
37
38#[async_trait]
39impl Runnable<String, bool> for BooleanParser {
40    async fn invoke(&self, input: String, _: RunnableConfig) -> Result<bool> {
41        OutputParser::parse(self, &input)
42    }
43    fn name(&self) -> &str {
44        "BooleanParser"
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn parses_truthy() {
54        let p = BooleanParser::new();
55        for s in ["yes", "YES", "true", "TRUE", "y", "1", " yes "] {
56            assert!(p.parse(s).unwrap(), "expected true for {s}");
57        }
58    }
59
60    #[test]
61    fn parses_falsy() {
62        let p = BooleanParser::new();
63        for s in ["no", "NO", "false", "n", "0"] {
64            assert!(!p.parse(s).unwrap(), "expected false for {s}");
65        }
66    }
67
68    #[test]
69    fn invalid_errors() {
70        let p = BooleanParser::new();
71        assert!(p.parse("maybe").is_err());
72    }
73}