2023-08-22 15:40:50 +00:00
use serde ::{ Deserialize , Serialize } ;
use std ::{
collections ::BTreeMap ,
fmt ::{ self , Display , Formatter } ,
} ;
2023-10-06 21:11:50 +00:00
use crate ::{ value ::Value , Error , Result , Table } ;
2023-08-22 15:40:50 +00:00
2023-10-18 21:42:36 +00:00
impl Serialize for VariableMap {
fn serialize < S > ( & self , serializer : S ) -> std ::result ::Result < S ::Ok , S ::Error >
where
S : serde ::Serializer ,
{
self . variables . serialize ( serializer )
}
}
2023-08-24 04:26:37 +00:00
/// A collection dust variables comprised of key-value pairs.
///
/// The inner value is a BTreeMap in order to allow VariableMap instances to be sorted and compared
/// to one another.
2023-10-18 21:42:36 +00:00
#[ derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Deserialize) ]
2023-08-22 15:40:50 +00:00
pub struct VariableMap {
variables : BTreeMap < String , Value > ,
}
impl VariableMap {
/// Creates a new instace.
pub fn new ( ) -> Self {
VariableMap {
variables : BTreeMap ::new ( ) ,
}
}
2023-08-24 02:39:32 +00:00
/// Returns a Value assigned to the identifer, allowing dot notation to retrieve Values that are /// nested in Lists or Maps. Returns None if there is no variable with a key matching the /// identifier. Returns an error if a Map or List is indexed incorrectly.
2023-08-22 15:40:50 +00:00
pub fn get_value ( & self , identifier : & str ) -> Result < Option < Value > > {
2023-08-24 02:03:26 +00:00
let split = identifier . rsplit_once ( '.' ) ;
let ( found_value , next_identifier ) = if let Some ( ( identifier , next_identifier ) ) = split {
if identifier . contains ( '.' ) {
( self . get_value ( identifier ) ? , next_identifier )
2023-08-22 15:40:50 +00:00
} else {
2023-08-24 02:03:26 +00:00
( self . variables . get ( identifier ) . cloned ( ) , next_identifier )
2023-08-22 15:40:50 +00:00
}
} else {
2023-08-24 02:03:26 +00:00
return Ok ( self . variables . get ( identifier ) . cloned ( ) ) ;
} ;
2023-08-22 15:40:50 +00:00
2023-08-24 02:03:26 +00:00
if let Some ( value ) = found_value {
if let Value ::List ( list ) = value {
let index = if let Ok ( index ) = next_identifier . parse ::< usize > ( ) {
index
} else {
2023-10-13 16:26:44 +00:00
return Err ( Error ::ExpectedInt {
actual : Value ::String ( next_identifier . to_string ( ) ) ,
} ) ;
2023-08-24 02:03:26 +00:00
} ;
Ok ( list . get ( index ) . cloned ( ) )
} else if let Value ::Map ( map ) = value {
map . get_value ( next_identifier )
2023-08-22 15:40:50 +00:00
} else {
2023-08-24 02:03:26 +00:00
Ok ( Some ( value ) )
2023-08-22 15:40:50 +00:00
}
2023-08-24 02:03:26 +00:00
} else {
Ok ( None )
2023-08-22 15:40:50 +00:00
}
}
2023-08-24 02:39:32 +00:00
/// Assigns a variable with a Value and the identifier as its key, allowing dot notation to
/// assign nested lists and maps. Returns an error if a List or Map is indexed incorrectly.
2023-10-02 19:19:48 +00:00
pub fn set_value ( & mut self , key : String , value : Value ) -> Result < ( ) > {
let split = key . split_once ( '.' ) ;
2023-08-22 15:40:50 +00:00
2023-08-24 04:26:37 +00:00
if let Some ( ( identifier , next_identifier ) ) = split {
let get_value = self . variables . get_mut ( identifier ) ;
2023-08-22 15:40:50 +00:00
2023-08-24 03:07:54 +00:00
if let Some ( found_value ) = get_value {
if let Value ::List ( list ) = found_value {
let index = if let Ok ( index ) = next_identifier . parse ::< usize > ( ) {
index
} else {
2023-10-13 16:26:44 +00:00
return Err ( Error ::ExpectedInt {
actual : Value ::String ( next_identifier . to_string ( ) ) ,
} ) ;
2023-08-24 03:07:54 +00:00
} ;
2023-08-29 02:07:20 +00:00
let mut missing_elements = index . saturating_sub ( list . len ( ) ) + 1 ;
2023-08-24 03:07:54 +00:00
while missing_elements > 0 {
list . push ( value . clone ( ) ) ;
missing_elements - = 1 ;
}
Ok ( ( ) )
} else if let Value ::Map ( map ) = found_value {
2023-10-02 19:19:48 +00:00
map . set_value ( next_identifier . to_string ( ) , value )
2023-08-22 15:40:50 +00:00
} else {
Err ( Error ::ExpectedMap {
2023-08-24 03:07:54 +00:00
actual : found_value . clone ( ) ,
2023-08-22 15:40:50 +00:00
} )
}
} else {
let mut new_map = VariableMap ::new ( ) ;
2023-10-02 19:19:48 +00:00
new_map . set_value ( next_identifier . to_string ( ) , value ) ? ;
2023-08-22 15:40:50 +00:00
self . variables
2023-08-24 04:26:37 +00:00
. insert ( identifier . to_string ( ) , Value ::Map ( new_map ) ) ;
2023-08-22 15:40:50 +00:00
Ok ( ( ) )
}
} else {
2023-10-02 19:19:48 +00:00
self . variables . insert ( key . to_string ( ) , value ) ;
2023-08-22 15:40:50 +00:00
Ok ( ( ) )
}
}
2023-10-23 19:01:00 +00:00
/// Removes an assigned variable.
2023-10-07 01:00:31 +00:00
///
/// TODO: Support dot notation.
pub fn remove ( & mut self , key : & str ) -> Option < Value > {
self . variables . remove ( key )
}
2023-08-22 15:40:50 +00:00
/// Returns a reference to the inner BTreeMap.
pub fn inner ( & self ) -> & BTreeMap < String , Value > {
& self . variables
}
/// Returns the number of stored variables.
pub fn len ( & self ) -> usize {
self . variables . len ( )
}
/// Returns true if the length is zero.
pub fn is_empty ( & self ) -> bool {
self . variables . is_empty ( )
}
}
impl Default for VariableMap {
fn default ( ) -> Self {
Self ::new ( )
}
}
impl Display for VariableMap {
fn fmt ( & self , f : & mut Formatter < '_ > ) -> fmt ::Result {
2023-10-14 18:18:13 +00:00
write! ( f , " {{ \n " ) ? ;
for ( key , value ) in & self . variables {
write! ( f , " {key} = {value} \n " ) ? ;
}
write! ( f , " }} " )
2023-08-22 15:40:50 +00:00
}
}
impl From < & Table > for VariableMap {
fn from ( value : & Table ) -> Self {
let mut map = VariableMap ::new ( ) ;
for ( row_index , row ) in value . rows ( ) . iter ( ) . enumerate ( ) {
2023-10-02 19:19:48 +00:00
map . set_value ( row_index . to_string ( ) , Value ::List ( row . clone ( ) ) )
2023-08-22 15:40:50 +00:00
. unwrap ( ) ;
}
map
}
}
#[ cfg(test) ]
mod tests {
use super ::* ;
#[ test ]
fn get_and_set_simple_value ( ) {
let mut map = VariableMap ::new ( ) ;
2023-10-05 12:03:14 +00:00
map . set_value ( " x " . to_string ( ) , Value ::Integer ( 1 ) ) . unwrap ( ) ;
2023-08-22 15:40:50 +00:00
2023-10-05 12:03:14 +00:00
assert_eq! ( Value ::Integer ( 1 ) , map . get_value ( " x " ) . unwrap ( ) . unwrap ( ) ) ;
2023-08-22 15:40:50 +00:00
}
#[ test ]
fn get_and_set_nested_maps ( ) {
let mut map = VariableMap ::new ( ) ;
2023-10-02 19:19:48 +00:00
map . set_value ( " x " . to_string ( ) , Value ::Map ( VariableMap ::new ( ) ) )
2023-08-22 15:40:50 +00:00
. unwrap ( ) ;
2023-10-02 19:19:48 +00:00
map . set_value ( " x.x " . to_string ( ) , Value ::Map ( VariableMap ::new ( ) ) )
2023-08-22 15:40:50 +00:00
. unwrap ( ) ;
2023-10-02 19:19:48 +00:00
map . set_value ( " x.x.x " . to_string ( ) , Value ::Map ( VariableMap ::new ( ) ) )
. unwrap ( ) ;
map . set_value ( " x.x.x.x " . to_string ( ) , Value ::Map ( VariableMap ::new ( ) ) )
2023-08-22 15:40:50 +00:00
. unwrap ( ) ;
assert_eq! (
Value ::Map ( VariableMap ::new ( ) ) ,
map . get_value ( " x.x.x.x " ) . unwrap ( ) . unwrap ( )
) ;
}
}