1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
pub( crate ) mod private
{
use crate::Type;
use std::collections::HashMap;
use former::Former;
/// A description of a Value in a command. Used to specify the expected type and provide a hint for the Value.
///
/// This struct is used to describe a command's subject or property and validate it against the expected type. It contains a hint
/// string that provides guidance to the user for entering a valid value, and a `Type` enum value that represents the expected
/// type of the value.
///
/// # Examples:
///
/// ```
/// # use wca::{ Type, ca::grammar::command::ValueDescription };
/// let value_desc = ValueDescription { kind: Type::String, hint: "Enter your name".to_string(), optional: false };
/// ```
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub struct ValueDescription
{
/// providing guidance to the user for entering a valid value
pub hint : String,
/// expected type of a value
pub kind : Type,
/// subject optional parameter
pub optional : bool,
}
/// Command descriptor.
///
/// Based on this structure, the structure( `ParsedCommand` ) obtained after parsing will be validated and converted to `VerifiedCommand`.
///
/// # Example:
///
/// ```
/// # use wca::{ Command, Type };
/// let command = Command::former()
/// .hint( "hint" )
/// .long_hint( "long_hint" )
/// .phrase( "command" )
/// .subject( "subject", Type::String, false )
/// .form();
/// ```
#[ derive( Debug, Clone, PartialEq, Eq ) ]
#[ derive( Former ) ]
pub struct Command
{
/// Command common hint.
#[ alias( h ) ]
pub hint : String,
/// Command full hint.
#[ alias( lh ) ]
pub long_hint : String,
/// Phrase descriptor for command.
pub phrase : String,
/// Command subjects hints and types.
pub subjects : Vec< ValueDescription >,
/// Hints and types for command options.
pub properties : HashMap< String, ValueDescription >,
/// Map of aliases.
// Aliased key -> Original key
pub properties_aliases : HashMap< String, String >,
// qqq : for Bohdan : routine should also be here
}
impl CommandFormer
{
/// Setter for separate properties.
pub fn subject< S : Into< String > >( mut self, hint : S, kind : Type, optional : bool ) -> Self
{
let hint = hint.into();
let subject = ValueDescription { hint, kind, optional };
let mut subjects = self.subjects.unwrap_or_default();
subjects.push( subject );
self.subjects = Some( subjects );
self
}
/// Setter for separate properties.
pub fn property< S : AsRef< str >, H : Into< String > >( mut self, key : S, hint : H, kind : Type, optional : bool ) -> Self
{
let key = key.as_ref();
let hint = hint.into();
let property = ValueDescription { hint, kind, optional };
let mut properties = self.properties.unwrap_or_default();
let properties_aliases = self.properties_aliases.unwrap_or_default();
debug_assert!( !properties.contains_key( key ), "Property name `{key}` is already used for `{:?}`", properties[ key ] );
debug_assert!( !properties_aliases.contains_key( key ), "Name `{key}` is already used for `{}` as alias", properties_aliases[ key ] );
properties.insert( key.into(), property );
self.properties = Some( properties );
self.properties_aliases = Some( properties_aliases );
self
}
// Setter for separate properties aliases.
pub fn property_alias< S : Into< String > >( mut self, key : S, alias : S ) -> Self
{
let key = key.into();
let alias = alias.into();
let properties = self.properties.unwrap_or_default();
let mut properties_aliases = self.properties_aliases.unwrap_or_default();
debug_assert!( !properties.contains_key( &alias ), "Name `{key}` is already used for `{:?} as property name`", properties[ &alias ] );
debug_assert!( !properties_aliases.contains_key( &alias ), "Alias `{alias}` is already used for `{}`", properties_aliases[ &alias ] );
properties_aliases.insert( alias, key );
self.properties = Some( properties );
self.properties_aliases = Some( properties_aliases );
self
}
}
}
//
crate::mod_interface!
{
exposed use Command;
protected use ValueDescription;
}
// qqq : use orphan instead of exposed for ALL files in the folder, dont use prelude for structs