1- use dbus:: { Message , arg:: { ArgType , RefArg } } ;
1+ use dbus:: { Message , arg:: { ArgType , RefArg , messageitem:: { MessageItemArray , MessageItem , MessageItemDict } } , Signature } ;
2+ use nu_plugin:: LabeledError ;
23use nu_protocol:: { Value , Span , Record } ;
4+ use std:: str:: FromStr ;
35
4- pub fn from_message ( message : & Message ) -> Result < Value , String > {
6+ use crate :: dbus_type:: DbusType ;
7+
8+ /// Get the arguments of a message as nushell Values
9+ pub fn from_message ( message : & Message ) -> Result < Vec < Value > , String > {
510 let mut out = vec ! [ ] ;
611 for refarg in message. iter_init ( ) {
712 out. push ( from_refarg ( & refarg) ?) ;
813 }
9- Ok ( Value :: list ( out, Span :: unknown ( ) ) )
14+ Ok ( out)
1015}
1116
1217pub fn from_refarg ( refarg : & dyn RefArg ) -> Result < Value , String > {
@@ -15,12 +20,12 @@ pub fn from_refarg(refarg: &dyn RefArg) -> Result<Value, String> {
1520 if refarg. signature ( ) . starts_with ( "a{" ) {
1621 // This is a dictionary
1722 let mut record = Record :: new ( ) ;
18- for entry in refarg. as_iter ( ) . unwrap ( ) {
19- let mut entry_iter = entry . as_iter ( ) . unwrap ( ) ;
20- let key = entry_iter . next ( ) . unwrap ( ) ;
21- let val = entry_iter . next ( ) . unwrap ( ) ;
22- if let Some ( key ) = key . as_str ( ) {
23- record . insert ( key , from_refarg ( val ) ? ) ;
23+ let mut iter = refarg. as_iter ( ) . unwrap ( ) ;
24+ while let Some ( key ) = iter . next ( ) {
25+ if let Some ( val ) = iter . next ( ) {
26+ if let Some ( key_str ) = key . as_str ( ) {
27+ record . insert ( key_str , from_refarg ( val ) ? ) ;
28+ }
2429 }
2530 }
2631 Value :: record ( record, Span :: unknown ( ) )
@@ -68,3 +73,156 @@ pub fn from_refarg(refarg: &dyn RefArg) -> Result<Value, String> {
6873 return Err ( "Encountered invalid D-Bus value" . into ( ) ) ,
6974 } )
7075}
76+
77+ pub fn to_message_item ( value : & Value , expected_type : Option < & DbusType > )
78+ -> Result < MessageItem , LabeledError >
79+ {
80+ // Report errors from conversion. Error must support Display
81+ macro_rules! try_convert {
82+ ( $result_expr: expr) => ( $result_expr. map_err( |err| LabeledError {
83+ label: format!( "Failed to convert value to the D-Bus `{:?}` type" ,
84+ expected_type. unwrap( ) ) ,
85+ msg: err. to_string( ) ,
86+ span: Some ( value. span( ) ) ,
87+ } ) ?)
88+ }
89+
90+ // Try to match values to expected types
91+ match ( value, expected_type) {
92+ // Boolean
93+ ( Value :: Bool { val, .. } , Some ( DbusType :: Boolean ) ) =>
94+ Ok ( MessageItem :: Bool ( * val) ) ,
95+
96+ // Strings and specialized strings
97+ ( Value :: String { val, .. } , Some ( DbusType :: String ) ) =>
98+ Ok ( MessageItem :: Str ( val. to_owned ( ) ) ) ,
99+ ( Value :: String { val, .. } , Some ( DbusType :: ObjectPath ) ) =>
100+ Ok ( MessageItem :: ObjectPath ( try_convert ! ( dbus:: strings:: Path :: new( val) ) ) ) ,
101+ ( Value :: String { val, .. } , Some ( DbusType :: Signature ) ) =>
102+ Ok ( MessageItem :: Signature ( try_convert ! ( dbus:: strings:: Signature :: new( val) ) ) ) ,
103+
104+ // Signed ints
105+ ( Value :: Int { val, .. } , Some ( DbusType :: Int64 ) ) =>
106+ Ok ( MessageItem :: Int64 ( * val) ) ,
107+ ( Value :: Int { val, .. } , Some ( DbusType :: Int32 ) ) =>
108+ Ok ( MessageItem :: Int32 ( try_convert ! ( i32 :: try_from( * val) ) ) ) ,
109+ ( Value :: Int { val, .. } , Some ( DbusType :: Int16 ) ) =>
110+ Ok ( MessageItem :: Int16 ( try_convert ! ( i16 :: try_from( * val) ) ) ) ,
111+
112+ // Unsigned ints
113+ ( Value :: Int { val, .. } , Some ( DbusType :: UInt64 ) ) =>
114+ Ok ( MessageItem :: UInt64 ( try_convert ! ( u64 :: try_from( * val) ) ) ) ,
115+ ( Value :: Int { val, .. } , Some ( DbusType :: UInt32 ) ) =>
116+ Ok ( MessageItem :: UInt32 ( try_convert ! ( u32 :: try_from( * val) ) ) ) ,
117+ ( Value :: Int { val, .. } , Some ( DbusType :: UInt16 ) ) =>
118+ Ok ( MessageItem :: UInt16 ( try_convert ! ( u16 :: try_from( * val) ) ) ) ,
119+ ( Value :: Int { val, .. } , Some ( DbusType :: Byte ) ) =>
120+ Ok ( MessageItem :: Byte ( try_convert ! ( u8 :: try_from( * val) ) ) ) ,
121+
122+ // Ints from string
123+ ( Value :: String { val, .. } , Some ( DbusType :: Int64 ) ) =>
124+ Ok ( MessageItem :: Int64 ( try_convert ! ( i64 :: from_str( & val[ ..] ) ) ) ) ,
125+ ( Value :: String { val, .. } , Some ( DbusType :: Int32 ) ) =>
126+ Ok ( MessageItem :: Int32 ( try_convert ! ( i32 :: from_str( & val[ ..] ) ) ) ) ,
127+ ( Value :: String { val, .. } , Some ( DbusType :: Int16 ) ) =>
128+ Ok ( MessageItem :: Int16 ( try_convert ! ( i16 :: from_str( & val[ ..] ) ) ) ) ,
129+ ( Value :: String { val, .. } , Some ( DbusType :: UInt64 ) ) =>
130+ Ok ( MessageItem :: UInt64 ( try_convert ! ( u64 :: from_str( & val[ ..] ) ) ) ) ,
131+ ( Value :: String { val, .. } , Some ( DbusType :: UInt32 ) ) =>
132+ Ok ( MessageItem :: UInt32 ( try_convert ! ( u32 :: from_str( & val[ ..] ) ) ) ) ,
133+ ( Value :: String { val, .. } , Some ( DbusType :: UInt16 ) ) =>
134+ Ok ( MessageItem :: UInt16 ( try_convert ! ( u16 :: from_str( & val[ ..] ) ) ) ) ,
135+ ( Value :: String { val, .. } , Some ( DbusType :: Byte ) ) =>
136+ Ok ( MessageItem :: Byte ( try_convert ! ( u8 :: from_str( & val[ ..] ) ) ) ) ,
137+
138+ // Float
139+ ( Value :: Float { val, .. } , Some ( DbusType :: Double ) ) =>
140+ Ok ( MessageItem :: Double ( * val) ) ,
141+ ( Value :: String { val, .. } , Some ( DbusType :: Double ) ) =>
142+ Ok ( MessageItem :: Double ( try_convert ! ( f64 :: from_str( & val[ ..] ) ) ) ) ,
143+
144+ // List/array
145+ ( Value :: List { vals, .. } , Some ( DbusType :: Array ( content_type) ) ) => {
146+ let content_sig = Signature :: from ( content_type. stringify ( ) ) ;
147+ let items = vals. iter ( )
148+ . map ( |content| to_message_item ( content, Some ( content_type) ) )
149+ . collect :: < Result < Vec < MessageItem > , _ > > ( ) ?;
150+ Ok ( MessageItem :: Array ( MessageItemArray :: new ( items, content_sig) . unwrap ( ) ) )
151+ } ,
152+
153+ // Struct
154+ ( Value :: List { vals, .. } , Some ( DbusType :: Struct ( types) ) ) => {
155+ if vals. len ( ) != types. len ( ) {
156+ return Err ( LabeledError {
157+ label : format ! ( "expected struct with {} element(s) ({:?})" , types. len( ) , types) ,
158+ msg : format ! ( "this list has {} element(s) instead" , vals. len( ) ) ,
159+ span : Some ( value. span ( ) )
160+ } ) ;
161+ }
162+ let items = vals. iter ( ) . zip ( types)
163+ . map ( |( content, r#type) | to_message_item ( content, Some ( r#type) ) )
164+ . collect :: < Result < Vec < MessageItem > , _ > > ( ) ?;
165+ Ok ( MessageItem :: Struct ( items) )
166+ } ,
167+
168+ // Record/dict
169+ ( Value :: Record { val, .. } , Some ( DbusType :: Array ( content_type) ) )
170+ if matches ! ( * * content_type, DbusType :: DictEntry ( _, _) ) =>
171+ {
172+ if let DbusType :: DictEntry ( ref key_type, ref val_type) = * * content_type {
173+ let key_sig = Signature :: from ( key_type. stringify ( ) ) ;
174+ let val_sig = Signature :: from ( val_type. stringify ( ) ) ;
175+ let pairs = val. iter ( )
176+ . map ( |( key, val) | {
177+ let key_as_value = Value :: string ( key, value. span ( ) ) ;
178+ let key_message_item = to_message_item ( & key_as_value, Some ( key_type) ) ?;
179+ let val_message_item = to_message_item ( val, Some ( val_type) ) ?;
180+ Ok ( ( key_message_item, val_message_item) )
181+ } )
182+ . collect :: < Result < Vec < _ > , LabeledError > > ( ) ?;
183+ Ok ( MessageItem :: Dict ( MessageItemDict :: new ( pairs, key_sig, val_sig) . unwrap ( ) ) )
184+ } else {
185+ unreachable ! ( )
186+ }
187+ } ,
188+
189+ // Variant - use automatic type
190+ ( other_value, Some ( DbusType :: Variant ) ) =>
191+ Ok ( MessageItem :: Variant ( Box :: new ( to_message_item ( other_value, None ) ?) ) ) ,
192+
193+ // Value not compatible with expected type
194+ ( other_value, Some ( expectation) ) =>
195+ Err ( LabeledError {
196+ label : format ! ( "`{}` can not be converted to the D-Bus `{:?}` type" ,
197+ other_value. get_type( ) , expectation) ,
198+ msg : format ! ( "expected a `{:?}` here" , expectation) ,
199+ span : Some ( other_value. span ( ) ) ,
200+ } ) ,
201+
202+ // Automatic types (with no type expectation)
203+ ( Value :: String { .. } , None ) =>
204+ to_message_item ( value, Some ( & DbusType :: String ) ) ,
205+ ( Value :: Int { .. } , None ) =>
206+ to_message_item ( value, Some ( & DbusType :: Int64 ) ) ,
207+ ( Value :: Float { .. } , None ) =>
208+ to_message_item ( value, Some ( & DbusType :: Double ) ) ,
209+ ( Value :: Bool { .. } , None ) =>
210+ to_message_item ( value, Some ( & DbusType :: Boolean ) ) ,
211+ ( Value :: List { .. } , None ) =>
212+ to_message_item ( value, Some ( & DbusType :: Array ( DbusType :: Variant . into ( ) ) ) ) ,
213+ ( Value :: Record { .. } , None ) =>
214+ to_message_item ( value, Some ( & DbusType :: Array (
215+ DbusType :: DictEntry (
216+ DbusType :: String . into ( ) ,
217+ DbusType :: Variant . into ( )
218+ ) . into ( ) ) ) ) ,
219+
220+ // No expected type, but can't handle this type
221+ _ =>
222+ Err ( LabeledError {
223+ label : format ! ( "can not use values of type `{}` in D-Bus calls" , value. get_type( ) ) ,
224+ msg : "use a supported type here instead" . into ( ) ,
225+ span : Some ( value. span ( ) ) ,
226+ } )
227+ }
228+ }
0 commit comments