@@ -1012,6 +1012,216 @@ impl PartialEq for Value {
10121012 }
10131013}
10141014
1015+ //=============================================================================
1016+ // Value Conversion Traits - FFI Support
1017+ //=============================================================================
1018+ // These traits enable ergonomic conversion between Rust types and Values,
1019+ // making FFI and native function implementation more convenient.
1020+
1021+ // From<T> for Value - infallible conversions (always succeed)
1022+
1023+ impl From < ( ) > for Value {
1024+ fn from ( _: ( ) ) -> Self {
1025+ Value :: nil ( )
1026+ }
1027+ }
1028+
1029+ impl From < bool > for Value {
1030+ fn from ( b : bool ) -> Self {
1031+ Value :: bool ( b)
1032+ }
1033+ }
1034+
1035+ impl From < i64 > for Value {
1036+ fn from ( n : i64 ) -> Self {
1037+ Value :: int ( n)
1038+ }
1039+ }
1040+
1041+ impl From < i32 > for Value {
1042+ fn from ( n : i32 ) -> Self {
1043+ Value :: int ( n as i64 )
1044+ }
1045+ }
1046+
1047+ impl From < usize > for Value {
1048+ fn from ( n : usize ) -> Self {
1049+ Value :: int ( n as i64 )
1050+ }
1051+ }
1052+
1053+ impl From < f64 > for Value {
1054+ fn from ( n : f64 ) -> Self {
1055+ Value :: float ( n)
1056+ }
1057+ }
1058+
1059+ impl From < & str > for Value {
1060+ fn from ( s : & str ) -> Self {
1061+ Value :: string ( s)
1062+ }
1063+ }
1064+
1065+ impl From < String > for Value {
1066+ fn from ( s : String ) -> Self {
1067+ Value :: string ( & s)
1068+ }
1069+ }
1070+
1071+ impl < T : Into < Value > > From < Vec < T > > for Value {
1072+ fn from ( v : Vec < T > ) -> Self {
1073+ let items: Vec < Value > = v. into_iter ( ) . map ( |x| x. into ( ) ) . collect ( ) ;
1074+ Value :: list ( items)
1075+ }
1076+ }
1077+
1078+ impl < T : Into < Value > > From < Option < T > > for Value {
1079+ fn from ( opt : Option < T > ) -> Self {
1080+ match opt {
1081+ Some ( v) => v. into ( ) ,
1082+ None => Value :: nil ( ) ,
1083+ }
1084+ }
1085+ }
1086+
1087+ // TryFrom<Value> for T - fallible conversions (can fail)
1088+
1089+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
1090+ pub struct ConversionError {
1091+ pub expected : & ' static str ,
1092+ pub got : String ,
1093+ }
1094+
1095+ impl fmt:: Display for ConversionError {
1096+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1097+ write ! ( f, "expected {}, got {}" , self . expected, self . got)
1098+ }
1099+ }
1100+
1101+ impl std:: error:: Error for ConversionError { }
1102+
1103+ impl TryFrom < Value > for bool {
1104+ type Error = ConversionError ;
1105+
1106+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1107+ value. as_bool ( ) . ok_or_else ( || ConversionError {
1108+ expected : "bool" ,
1109+ got : value. type_name ( ) . to_string ( ) ,
1110+ } )
1111+ }
1112+ }
1113+
1114+ impl TryFrom < Value > for i64 {
1115+ type Error = ConversionError ;
1116+
1117+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1118+ value. as_int ( ) . ok_or_else ( || ConversionError {
1119+ expected : "int" ,
1120+ got : value. type_name ( ) . to_string ( ) ,
1121+ } )
1122+ }
1123+ }
1124+
1125+ impl TryFrom < Value > for i32 {
1126+ type Error = ConversionError ;
1127+
1128+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1129+ let n = value. as_int ( ) . ok_or_else ( || ConversionError {
1130+ expected : "int" ,
1131+ got : value. type_name ( ) . to_string ( ) ,
1132+ } ) ?;
1133+ i32:: try_from ( n) . map_err ( |_| ConversionError {
1134+ expected : "int32" ,
1135+ got : format ! ( "int64 out of range: {}" , n) ,
1136+ } )
1137+ }
1138+ }
1139+
1140+ impl TryFrom < Value > for usize {
1141+ type Error = ConversionError ;
1142+
1143+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1144+ let n = value. as_int ( ) . ok_or_else ( || ConversionError {
1145+ expected : "int" ,
1146+ got : value. type_name ( ) . to_string ( ) ,
1147+ } ) ?;
1148+ if n < 0 {
1149+ return Err ( ConversionError {
1150+ expected : "non-negative int" ,
1151+ got : format ! ( "{}" , n) ,
1152+ } ) ;
1153+ }
1154+ Ok ( n as usize )
1155+ }
1156+ }
1157+
1158+ impl TryFrom < Value > for f64 {
1159+ type Error = ConversionError ;
1160+
1161+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1162+ // Allow both float and int -> float conversion
1163+ if let Some ( f) = value. as_float ( ) {
1164+ Ok ( f)
1165+ } else if let Some ( i) = value. as_int ( ) {
1166+ Ok ( i as f64 )
1167+ } else {
1168+ Err ( ConversionError {
1169+ expected : "float or int" ,
1170+ got : value. type_name ( ) . to_string ( ) ,
1171+ } )
1172+ }
1173+ }
1174+ }
1175+
1176+ impl TryFrom < Value > for String {
1177+ type Error = ConversionError ;
1178+
1179+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1180+ value
1181+ . as_string ( )
1182+ . map ( |s| s. to_string ( ) )
1183+ . ok_or_else ( || ConversionError {
1184+ expected : "string" ,
1185+ got : value. type_name ( ) . to_string ( ) ,
1186+ } )
1187+ }
1188+ }
1189+
1190+ impl TryFrom < Value > for Vec < Value > {
1191+ type Error = ConversionError ;
1192+
1193+ fn try_from ( value : Value ) -> Result < Self , Self :: Error > {
1194+ if value. is_nil ( ) {
1195+ return Ok ( Vec :: new ( ) ) ;
1196+ }
1197+
1198+ // Handle array lists
1199+ if let Some ( items) = value. as_list ( ) {
1200+ return Ok ( items. to_vec ( ) ) ;
1201+ }
1202+
1203+ // Handle cons cells - traverse and collect
1204+ if value. as_cons ( ) . is_some ( ) {
1205+ let mut result = Vec :: new ( ) ;
1206+ let mut current = value;
1207+ while let Some ( cons) = current. as_cons ( ) {
1208+ result. push ( cons. car . clone ( ) ) ;
1209+ current = cons. cdr . clone ( ) ;
1210+ }
1211+ // If ended on array list, append it
1212+ if let Some ( items) = current. as_list ( ) {
1213+ result. extend_from_slice ( items) ;
1214+ }
1215+ return Ok ( result) ;
1216+ }
1217+
1218+ Err ( ConversionError {
1219+ expected : "list" ,
1220+ got : value. type_name ( ) . to_string ( ) ,
1221+ } )
1222+ }
1223+ }
1224+
10151225#[ cfg( test) ]
10161226mod tests {
10171227 use super :: * ;
@@ -1399,4 +1609,171 @@ mod tests {
13991609
14001610 super :: clear_arena ( ) ;
14011611 }
1612+
1613+ // Conversion trait tests
1614+ #[ test]
1615+ fn test_from_bool ( ) {
1616+ let v: Value = true . into ( ) ;
1617+ assert_eq ! ( v. as_bool( ) , Some ( true ) ) ;
1618+ let v: Value = false . into ( ) ;
1619+ assert_eq ! ( v. as_bool( ) , Some ( false ) ) ;
1620+ }
1621+
1622+ #[ test]
1623+ fn test_from_integers ( ) {
1624+ let v: Value = 42i64 . into ( ) ;
1625+ assert_eq ! ( v. as_int( ) , Some ( 42 ) ) ;
1626+
1627+ let v: Value = 42i32 . into ( ) ;
1628+ assert_eq ! ( v. as_int( ) , Some ( 42 ) ) ;
1629+
1630+ let v: Value = 42usize . into ( ) ;
1631+ assert_eq ! ( v. as_int( ) , Some ( 42 ) ) ;
1632+ }
1633+
1634+ #[ test]
1635+ fn test_from_float ( ) {
1636+ let v: Value = 3.14f64 . into ( ) ;
1637+ assert_eq ! ( v. as_float( ) , Some ( 3.14 ) ) ;
1638+ }
1639+
1640+ #[ test]
1641+ fn test_from_string ( ) {
1642+ let v: Value = "hello" . into ( ) ;
1643+ assert_eq ! ( v. as_string( ) , Some ( "hello" ) ) ;
1644+
1645+ let v: Value = String :: from ( "world" ) . into ( ) ;
1646+ assert_eq ! ( v. as_string( ) , Some ( "world" ) ) ;
1647+ }
1648+
1649+ #[ test]
1650+ fn test_from_vec ( ) {
1651+ let v: Value = vec ! [ 1i64 , 2i64 , 3i64 ] . into ( ) ;
1652+ let list = v. as_list ( ) . unwrap ( ) ;
1653+ assert_eq ! ( list. len( ) , 3 ) ;
1654+ assert_eq ! ( list[ 0 ] . as_int( ) , Some ( 1 ) ) ;
1655+ assert_eq ! ( list[ 2 ] . as_int( ) , Some ( 3 ) ) ;
1656+ }
1657+
1658+ #[ test]
1659+ fn test_from_option ( ) {
1660+ let v: Value = Some ( 42i64 ) . into ( ) ;
1661+ assert_eq ! ( v. as_int( ) , Some ( 42 ) ) ;
1662+
1663+ let v: Value = None :: < i64 > . into ( ) ;
1664+ assert ! ( v. is_nil( ) ) ;
1665+ }
1666+
1667+ #[ test]
1668+ fn test_from_unit ( ) {
1669+ let v: Value = ( ) . into ( ) ;
1670+ assert ! ( v. is_nil( ) ) ;
1671+ }
1672+
1673+ #[ test]
1674+ fn test_try_from_bool ( ) {
1675+ use std:: convert:: TryFrom ;
1676+
1677+ let v = Value :: bool ( true ) ;
1678+ assert_eq ! ( bool :: try_from( v) , Ok ( true ) ) ;
1679+
1680+ let v = Value :: int ( 42 ) ;
1681+ assert ! ( bool :: try_from( v) . is_err( ) ) ;
1682+ }
1683+
1684+ #[ test]
1685+ fn test_try_from_i64 ( ) {
1686+ use std:: convert:: TryFrom ;
1687+
1688+ let v = Value :: int ( 42 ) ;
1689+ assert_eq ! ( i64 :: try_from( v) , Ok ( 42 ) ) ;
1690+
1691+ let v = Value :: bool ( true ) ;
1692+ assert ! ( i64 :: try_from( v) . is_err( ) ) ;
1693+ }
1694+
1695+ #[ test]
1696+ fn test_try_from_i32 ( ) {
1697+ use std:: convert:: TryFrom ;
1698+
1699+ let v = Value :: int ( 42 ) ;
1700+ assert_eq ! ( i32 :: try_from( v) , Ok ( 42 ) ) ;
1701+
1702+ // Test overflow - use value definitely outside i32 range
1703+ let v = Value :: int ( i32:: MAX as i64 + 1 ) ;
1704+ assert ! ( i32 :: try_from( v) . is_err( ) ) ;
1705+ }
1706+
1707+ #[ test]
1708+ fn test_try_from_usize ( ) {
1709+ use std:: convert:: TryFrom ;
1710+
1711+ let v = Value :: int ( 42 ) ;
1712+ assert_eq ! ( usize :: try_from( v) , Ok ( 42 ) ) ;
1713+
1714+ // Test negative
1715+ let v = Value :: int ( -1 ) ;
1716+ assert ! ( usize :: try_from( v) . is_err( ) ) ;
1717+ }
1718+
1719+ #[ test]
1720+ fn test_try_from_f64 ( ) {
1721+ use std:: convert:: TryFrom ;
1722+
1723+ let v = Value :: float ( 3.14 ) ;
1724+ assert_eq ! ( f64 :: try_from( v) , Ok ( 3.14 ) ) ;
1725+
1726+ // Should also work for int -> float
1727+ let v = Value :: int ( 42 ) ;
1728+ assert_eq ! ( f64 :: try_from( v) , Ok ( 42.0 ) ) ;
1729+
1730+ let v = Value :: bool ( true ) ;
1731+ assert ! ( f64 :: try_from( v) . is_err( ) ) ;
1732+ }
1733+
1734+ #[ test]
1735+ fn test_try_from_string ( ) {
1736+ use std:: convert:: TryFrom ;
1737+
1738+ let v = Value :: string ( "hello" ) ;
1739+ assert_eq ! ( String :: try_from( v) , Ok ( "hello" . to_string( ) ) ) ;
1740+
1741+ let v = Value :: int ( 42 ) ;
1742+ assert ! ( String :: try_from( v) . is_err( ) ) ;
1743+ }
1744+
1745+ #[ test]
1746+ fn test_try_from_vec ( ) {
1747+ use std:: convert:: TryFrom ;
1748+
1749+ let v = Value :: list ( vec ! [ Value :: int( 1 ) , Value :: int( 2 ) , Value :: int( 3 ) ] ) ;
1750+ let vec = Vec :: < Value > :: try_from ( v) . unwrap ( ) ;
1751+ assert_eq ! ( vec. len( ) , 3 ) ;
1752+ assert_eq ! ( vec[ 0 ] . as_int( ) , Some ( 1 ) ) ;
1753+
1754+ // Test nil -> empty vec
1755+ let v = Value :: nil ( ) ;
1756+ let vec = Vec :: < Value > :: try_from ( v) . unwrap ( ) ;
1757+ assert_eq ! ( vec. len( ) , 0 ) ;
1758+
1759+ // Test cons cells
1760+ let v = Value :: cons ( Value :: int ( 1 ) , Value :: cons ( Value :: int ( 2 ) , Value :: nil ( ) ) ) ;
1761+ let vec = Vec :: < Value > :: try_from ( v) . unwrap ( ) ;
1762+ assert_eq ! ( vec. len( ) , 2 ) ;
1763+ assert_eq ! ( vec[ 0 ] . as_int( ) , Some ( 1 ) ) ;
1764+ assert_eq ! ( vec[ 1 ] . as_int( ) , Some ( 2 ) ) ;
1765+
1766+ // Test error case
1767+ let v = Value :: int ( 42 ) ;
1768+ assert ! ( Vec :: <Value >:: try_from( v) . is_err( ) ) ;
1769+ }
1770+
1771+ #[ test]
1772+ fn test_conversion_error_display ( ) {
1773+ let err = super :: ConversionError {
1774+ expected : "int" ,
1775+ got : "string" . to_string ( ) ,
1776+ } ;
1777+ assert_eq ! ( format!( "{}" , err) , "expected int, got string" ) ;
1778+ }
14021779}
0 commit comments