use super::ValidationError;
use crate::{ElicitCommunicator, ElicitResult, Elicitation, Prompt};
use elicitation_macros::instrumented_impl;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BoolTrue(bool);
#[cfg_attr(not(kani), instrumented_impl)]
impl BoolTrue {
pub fn new(value: bool) -> Result<Self, ValidationError> {
if value {
Ok(Self(value))
} else {
Err(ValidationError::NotTrue)
}
}
pub fn get(&self) -> bool {
self.0
}
pub fn into_inner(self) -> bool {
self.0
}
}
crate::default_style!(BoolTrue => BoolTrueStyle);
impl Prompt for BoolTrue {
fn prompt() -> Option<&'static str> {
Some("Please confirm (must be true):")
}
}
impl Elicitation for BoolTrue {
type Style = BoolTrueStyle;
#[tracing::instrument(skip(communicator), fields(type_name = "BoolTrue"))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting BoolTrue (must be true)");
loop {
let value = bool::elicit(communicator).await?;
match Self::new(value) {
Ok(bool_true) => {
tracing::debug!(value, "Valid BoolTrue constructed");
return Ok(bool_true);
}
Err(e) => {
tracing::warn!(value, error = %e, "Invalid BoolTrue, re-prompting");
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BoolFalse(bool);
impl BoolFalse {
pub fn new(value: bool) -> Result<Self, ValidationError> {
if !value {
Ok(Self(value))
} else {
Err(ValidationError::NotFalse)
}
}
pub fn get(&self) -> bool {
self.0
}
pub fn into_inner(self) -> bool {
self.0
}
}
crate::default_style!(BoolFalse => BoolFalseStyle);
impl Prompt for BoolFalse {
fn prompt() -> Option<&'static str> {
Some("Please deny (must be false):")
}
}
impl Elicitation for BoolFalse {
type Style = BoolFalseStyle;
#[tracing::instrument(skip(communicator), fields(type_name = "BoolFalse"))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting BoolFalse (must be false)");
loop {
let value = bool::elicit(communicator).await?;
match Self::new(value) {
Ok(bool_false) => {
tracing::debug!(value, "Valid BoolFalse constructed");
return Ok(bool_false);
}
Err(e) => {
tracing::warn!(value, error = %e, "Invalid BoolFalse, re-prompting");
}
}
}
}
}
#[cfg(test)]
mod bool_true_tests {
use super::*;
#[test]
fn bool_true_new_valid() {
let result = BoolTrue::new(true);
assert!(result.is_ok());
assert!(result.unwrap().get());
}
#[test]
fn bool_true_new_false_invalid() {
let result = BoolTrue::new(false);
assert!(result.is_err());
}
#[test]
fn bool_true_into_inner() {
let bool_true = BoolTrue::new(true).unwrap();
let value: bool = bool_true.into_inner();
assert!(value);
}
}
#[cfg(test)]
mod bool_false_tests {
use super::*;
#[test]
fn bool_false_new_valid() {
let result = BoolFalse::new(false);
assert!(result.is_ok());
assert!(!result.unwrap().get());
}
#[test]
fn bool_false_new_true_invalid() {
let result = BoolFalse::new(true);
assert!(result.is_err());
}
#[test]
fn bool_false_into_inner() {
let bool_false = BoolFalse::new(false).unwrap();
let value: bool = bool_false.into_inner();
assert!(!value);
}
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
schemars::JsonSchema,
)]
#[schemars(description = "A boolean value")]
pub struct BoolDefault(#[schemars(description = "True or false")] bool);
impl BoolDefault {
pub fn new(b: bool) -> Self {
Self(b)
}
pub fn get(&self) -> bool {
self.0
}
pub fn into_inner(self) -> bool {
self.0
}
}
rmcp::elicit_safe!(BoolDefault);
crate::default_style!(BoolDefault => BoolDefaultStyle);
impl Prompt for BoolDefault {
fn prompt() -> Option<&'static str> {
Some("Please enter true or false:")
}
}
impl Elicitation for BoolDefault {
type Style = BoolDefaultStyle;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
let prompt = Self::prompt().ok_or_else(|| {
crate::ElicitError::new(crate::ElicitErrorKind::InvalidFormat {
expected: "valid prompt".to_string(),
received: "None".to_string(),
})
})?;
tracing::debug!("Eliciting BoolDefault with server-side send_prompt");
let response = communicator.send_prompt(prompt).await?;
let value: bool = response.trim().parse().map_err(|e| {
crate::ElicitError::new(crate::ElicitErrorKind::ParseError(format!(
"Failed to parse bool: {}",
e
)))
})?;
Ok(Self::new(value))
}
}