rhai_rusp/
lib.rs

1//! `rhai-rusp` offers `Rhai` bindings for the `Rust` `USP` (or
2//! [`rusp`](https://crates.io/crates/rusp) library to for comfortable introspection, creation, and
3//! manipulation of [`USP`](https://usp.technology) protocol communication primitives.
4use rhai::def_package;
5use rhai::{
6    plugin::{
7        combine_with_exported_module, export_module, mem, Dynamic, EvalAltResult, FnNamespace,
8        FuncRegistration, ImmutableString, Module, NativeCallContext, PluginFunc, RhaiResult,
9        TypeId,
10    },
11    Array, Blob, Map, Variant,
12};
13use rusp_lib::usp::{Body, Msg};
14use rusp_lib::usp_builder;
15use rusp_lib::usp_record::{self, Record};
16
17/// Evaluate a Rhai script in the context of the `rusp` package and return a supported type, like
18/// [`Record`], [`Msg`] or [`String`]
19///
20/// E.g. you can do:
21/// ```
22/// let script = r#"
23/// // Rhai script
24/// rusp::record_builder()
25///   .with_to_id("proto::to")
26///   .with_from_id("proto::from")
27///   .as_disconnect_record("Bye", 0)
28///   .build()
29/// "#;
30/// let record = rhai_rusp::eval_rusp::<rusp_lib::usp_record::Record>(script).unwrap();
31/// ```
32///
33/// # Errors
34///
35/// This function will return `Err` containing a textual description of the encountered error if
36/// the provided Rhai script fails to evaluate.
37pub fn eval_rusp<T>(str: &str) -> Result<T, String>
38where
39    T: Variant + Clone,
40{
41    use rhai::{packages::Package, Engine};
42
43    let mut engine = Engine::new();
44    engine.register_static_module("rusp", RuspPackage::new().as_shared_module());
45
46    engine.eval::<T>(str).map_err(|e| e.to_string())
47}
48
49/// Supply Rusp [`Record`] generation functionality
50///
51/// The general usage pattern from within a Rhai script is straight forward: First you obtain a
52/// builder type by calling `rusp::record_builder()`, then add data using any of the available
53/// builder methods and in the end obtain the [`Record`] structure by calling `build()`.
54///
55/// Here's a full example:
56/// ```
57/// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,MQTTConnectRecord,mod_MQTTConnectRecord::MQTTVersion,Record};
58/// // Rhai script
59/// # let script = r#"
60/// rusp::record_builder()
61///   .with_version("1.3")
62///   .with_to_id("proto::to")
63///   .with_from_id("proto::from")
64///   .as_mqtt_connect_record("V5", "/topic")
65///   .build()
66/// # "#;
67/// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
68/// # assert_eq!(record.to_id, "proto::to");
69/// # assert_eq!(record.from_id, "proto::from");
70/// # assert_eq!(record.record_type, OneOfrecord_type::mqtt_connect(MQTTConnectRecord { subscribed_topic: "/topic".into(), version: MQTTVersion::V5 }));
71/// ```
72#[export_module]
73pub mod rhai_rusp_record {
74    use usp_builder::RecordBuilder;
75
76    /// Sets up a new USP `RecordBuilder`
77    #[must_use]
78    pub const fn record_builder() -> RecordBuilder {
79        RecordBuilder::new()
80    }
81
82    /// Sets the version of the USP standard being used by the [`Record`]
83    /// ```
84    /// # use rusp_lib::usp_record::Record;
85    /// // Rhai script
86    /// # let script = r#"
87    /// rusp::record_builder()
88    ///   .with_version("1.3")
89    ///   .build()
90    /// # "#;
91    /// # let record = rhai_rusp::eval_rusp::<Record>(script);
92    /// ```
93    #[rhai_fn(global)]
94    #[must_use]
95    pub fn with_version(builder: RecordBuilder, version: &str) -> RecordBuilder {
96        builder.with_version(version.into())
97    }
98
99    /// Sets the recipient endpoint id of the [`Record`]
100    /// ```
101    /// # use rusp_lib::usp_record::Record;
102    /// // Rhai script
103    /// # let script = r#"
104    /// rusp::record_builder()
105    ///   .with_to_id("proto::controller")
106    ///   .build()
107    /// # "#;
108    /// # let record = rhai_rusp::eval_rusp::<Record>(script);
109    /// ```
110    #[rhai_fn(global)]
111    #[must_use]
112    pub fn with_to_id(builder: RecordBuilder, id: &str) -> RecordBuilder {
113        builder.with_to_id(id.into())
114    }
115
116    /// Sets the sender endpoint id of the [`Record`]
117    /// ```
118    /// # use rusp_lib::usp_record::Record;
119    /// // Rhai script
120    /// # let script = r#"
121    /// rusp::record_builder()
122    ///   .with_from_id("proto::agent")
123    ///   .build()
124    /// # "#;
125    /// # let record = rhai_rusp::eval_rusp::<Record>(script);
126    /// ```
127    #[rhai_fn(global)]
128    #[must_use]
129    pub fn with_from_id(builder: RecordBuilder, id: &str) -> RecordBuilder {
130        builder.with_from_id(id.into())
131    }
132
133    /// Assigns the provided [`Msg`] as the "no session context" payload of the [`Record`]
134    /// ```
135    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type, NoSessionContextRecord, Record};
136    ///
137    /// // Rhai script
138    /// # let script = r#"
139    /// let body = rusp::get_builder()
140    ///   .with_params(["Device."])
141    ///   .build();
142    /// let msg = rusp::msg_builder()
143    ///   .with_msg_id("Foo")
144    ///   .with_body(body)
145    ///   .build();
146    /// rusp::record_builder()
147    ///   .with_version("1.2")
148    ///   .with_to_id("proto::to")
149    ///   .with_from_id("proto::from")
150    ///   .with_no_session_context_payload(msg)
151    ///   .build()
152    /// # "#;
153    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
154    ///
155    /// # assert_eq!(record.version, "1.2");
156    /// # assert_eq!(record.to_id, "proto::to");
157    /// # assert_eq!(record.from_id, "proto::from");
158    /// # assert!(matches!(record.record_type, OneOfrecord_type::no_session_context(NoSessionContextRecord { .. })));
159    /// ```
160    #[rhai_fn(global)]
161    #[must_use]
162    pub fn with_no_session_context_payload(builder: RecordBuilder, payload: Msg) -> RecordBuilder {
163        builder.with_no_session_context_payload(&payload)
164    }
165
166    /// Designates the [`Record`] to be of type WebSocketConnectRecord
167    /// ```
168    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,WebSocketConnectRecord,Record};
169    /// // Rhai script
170    /// # let script = r#"
171    /// rusp::record_builder()
172    ///   .with_version("1.3")
173    ///   .with_to_id("proto::to")
174    ///   .with_from_id("proto::from")
175    ///   .as_websocket_connect_record()
176    ///   .build()
177    /// # "#;
178    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
179    /// # assert_eq!(record.to_id, "proto::to");
180    /// # assert_eq!(record.from_id, "proto::from");
181    /// # assert_eq!(record.record_type, OneOfrecord_type::websocket_connect(WebSocketConnectRecord { }));
182    /// ```
183    #[rhai_fn(global)]
184    #[must_use]
185    pub fn as_websocket_connect_record(builder: RecordBuilder) -> RecordBuilder {
186        builder.as_websocket_connect_record()
187    }
188
189    /// Designates the [`Record`] to be of type MQTTConnectRecord
190    /// ```
191    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,MQTTConnectRecord,mod_MQTTConnectRecord::MQTTVersion,Record};
192    /// // Rhai script
193    /// # let script = r#"
194    /// rusp::record_builder()
195    ///   .with_to_id("proto::to")
196    ///   .with_from_id("proto::from")
197    ///   .as_mqtt_connect_record("V5", "/topic")
198    ///   .build()
199    /// # "#;
200    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
201    /// # assert_eq!(record.to_id, "proto::to");
202    /// # assert_eq!(record.from_id, "proto::from");
203    /// # assert_eq!(record.record_type, OneOfrecord_type::mqtt_connect(MQTTConnectRecord { subscribed_topic: "/topic".into(), version: MQTTVersion::V5 }));
204    /// ```
205    ///
206    /// # Errors
207    ///
208    /// This function will return `Err` if the provided `version` is not `V3_1_1` or `V5`.
209    #[rhai_fn(global, return_raw)]
210    pub fn as_mqtt_connect_record(
211        builder: RecordBuilder,
212        version: &str,
213        subscribed_topic: &str,
214    ) -> Result<RecordBuilder, Box<EvalAltResult>> {
215        use usp_record::mod_MQTTConnectRecord::MQTTVersion;
216
217        let version = match version {
218            "V3_1_1" | "V5" => MQTTVersion::from(version),
219            _ => return Err("MQTT version must be either V3_1_1 or V5".into()),
220        };
221
222        Ok(builder.as_mqtt_connect_record(version, subscribed_topic.into()))
223    }
224
225    /// Designates the [`Record`] to be of type STOMPConnectRecord
226    /// ```
227    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,STOMPConnectRecord,mod_STOMPConnectRecord::STOMPVersion,Record};
228    /// // Rhai script
229    /// # let script = r#"
230    /// rusp::record_builder()
231    ///   .with_to_id("proto::to")
232    ///   .with_from_id("proto::from")
233    ///   .as_stomp_connect_record("V1_2", "/dest")
234    ///   .build()
235    /// # "#;
236    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
237    /// # assert_eq!(record.to_id, "proto::to");
238    /// # assert_eq!(record.from_id, "proto::from");
239    /// # assert_eq!(record.record_type, OneOfrecord_type::stomp_connect(STOMPConnectRecord { subscribed_destination: "/dest".into(), version: STOMPVersion::V1_2 }));
240    /// ```
241    ///
242    /// # Errors
243    ///
244    /// This function will return `Err` if the provided `version` is not `V1_2`.
245    #[rhai_fn(global, return_raw)]
246    pub fn as_stomp_connect_record(
247        builder: RecordBuilder,
248        version: &str,
249        subscribed_destination: &str,
250    ) -> Result<RecordBuilder, Box<EvalAltResult>> {
251        use usp_record::mod_STOMPConnectRecord::STOMPVersion;
252
253        let version = match version {
254            "V1_2" => STOMPVersion::from(version),
255            _ => return Err("STOMP version must be V1_2".into()),
256        };
257
258        Ok(builder.as_stomp_connect_record(version, subscribed_destination.into()))
259    }
260
261    /// Designates the [`Record`] to be of type DisconnectRecord
262    /// ```
263    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,DisconnectRecord,Record};
264    /// // Rhai script
265    /// # let script = r#"
266    /// rusp::record_builder()
267    ///   .with_to_id("proto::to")
268    ///   .with_from_id("proto::from")
269    ///   .as_disconnect_record("Bye", 0)
270    ///   .build()
271    /// # "#;
272    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
273    /// # assert_eq!(record.to_id, "proto::to");
274    /// # assert_eq!(record.from_id, "proto::from");
275    /// # assert_eq!(record.record_type, OneOfrecord_type::disconnect(DisconnectRecord { reason: "Bye".into(), reason_code: 0 }));
276    /// ```
277    #[rhai_fn(global)]
278    #[must_use]
279    pub fn as_disconnect_record(
280        builder: RecordBuilder,
281        reason: &str,
282        reason_code: i64,
283    ) -> RecordBuilder {
284        builder.as_disconnect_record(reason.into(), u32::try_from(reason_code).unwrap_or(7003))
285    }
286
287    /// Designates the [`Record`] to be of type UDSConnectRecord
288    /// ```
289    /// # use rusp_lib::usp_record::{mod_Record::OneOfrecord_type,UDSConnectRecord,Record};
290    /// // Rhai script
291    /// # let script = r#"
292    /// rusp::record_builder()
293    ///   .with_to_id("proto::to")
294    ///   .with_from_id("proto::from")
295    ///   .as_uds_connect_record()
296    ///   .build()
297    /// # "#;
298    /// # let record = rhai_rusp::eval_rusp::<Record>(script).unwrap();
299    /// # assert_eq!(record.to_id, "proto::to");
300    /// # assert_eq!(record.from_id, "proto::from");
301    /// # assert_eq!(record.record_type, OneOfrecord_type::uds_connect(UDSConnectRecord {}));
302    /// ```
303    #[rhai_fn(global)]
304    #[must_use]
305    pub fn as_uds_connect_record(builder: RecordBuilder) -> RecordBuilder {
306        builder.as_uds_connect_record()
307    }
308
309    /// Turns the builder into a [`Record`] structure
310    ///
311    /// # Errors
312    ///
313    /// This function will return `Err` if the provided `builder` was set up with incomplete or
314    /// incorrect data.
315    #[rhai_fn(global, return_raw)]
316    pub fn build(builder: RecordBuilder) -> Result<Record, Box<EvalAltResult>> {
317        Ok(builder.build().map_err(|e| e.to_string())?)
318    }
319}
320
321/// Supply Rusp [`Msg`] generation functionality
322/// ```
323/// // Rhai script
324/// # let script = r#"
325/// rusp::msg_builder()
326///   .with_msg_id("Foo")
327///   .build()
328/// "#;
329/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script);
330///
331/// // This will result in an `Err`:
332/// // Err("Runtime error: Cannot produce USP Msg without msg_body (line 8, position 10)")
333/// # assert!(msg.is_err());
334/// ```
335///
336/// ```
337/// // Rhai script
338/// # let script = r#"
339/// let body = rusp::get_builder()
340///   .with_params(["Device."])
341///   .build();
342/// rusp::msg_builder()
343///   .with_body(body)
344///   .build()
345/// "#;
346/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script);
347///
348/// // This will result in an `Err`:
349/// // Err("Runtime error: Cannot produce USP Msg without msg_id (line 8, position 10)")
350/// # assert!(msg.is_err());
351/// ```
352///
353/// ```
354/// // Rhai script
355/// # let script = r#"
356/// let body = rusp::get_builder()
357///   .with_params(["Device."])
358///   .build();
359/// rusp::msg_builder()
360///   .with_msg_id("Foo")
361///   .with_body(body)
362///   .build()
363/// "#;
364/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
365/// # assert!(!msg.is_error());
366/// # assert!(msg.is_request());
367/// ```
368#[export_module]
369pub mod rhai_rusp_msg {
370    use usp_builder::MsgBuilder;
371
372    /// Sets up a new USP `MsgBuilder`
373    #[must_use]
374    pub const fn msg_builder() -> MsgBuilder {
375        MsgBuilder::new()
376    }
377
378    /// Sets the `msg_id` of the [`Msg`]
379    /// ```
380    /// # use rusp_lib::usp::Msg;
381    /// // Rhai script
382    /// # let script = r#"
383    /// rusp::msg_builder()
384    ///   .with_msg_id("Foo")
385    ///   .build()
386    /// # "#;
387    /// # let msg = rhai_rusp::eval_rusp::<Msg>(script);
388    /// ```
389    #[rhai_fn(global)]
390    #[must_use]
391    pub fn with_msg_id(builder: MsgBuilder, msg_id: &str) -> MsgBuilder {
392        builder.with_msg_id(msg_id.into())
393    }
394
395    /// Sets the `body` of the [`Msg`]
396    /// ```
397    /// # use rusp_lib::usp::Msg;
398    /// // Rhai script
399    /// # let script = r#"
400    /// let body = rusp::get_builder()
401    ///   .with_params(["Device."])
402    ///   .build();
403    /// rusp::msg_builder()
404    ///   .with_msg_id("Foo")
405    ///   .with_body(body)
406    ///   .build()
407    /// # "#;
408    /// # let msg = rhai_rusp::eval_rusp::<Msg>(script);
409    /// ```
410    #[rhai_fn(global)]
411    #[must_use]
412    pub fn with_body(builder: MsgBuilder, body: Body) -> MsgBuilder {
413        builder.with_body(body)
414    }
415
416    /// Turns the builder into a [`Msg`] structure
417    ///
418    /// # Errors
419    ///
420    /// This function will return `Err` if the provided `builder` was set up with incomplete or
421    /// incorrect data.
422    #[rhai_fn(global, return_raw)]
423    pub fn build(builder: MsgBuilder) -> Result<Msg, Box<EvalAltResult>> {
424        Ok(builder.build().map_err(|e| e.to_string())?)
425    }
426}
427
428/// Supply Rusp Delete Message functionality
429/// ```
430/// // Rhai script
431/// # let script = r#"
432/// let body = rusp::delete_builder()
433///   .with_allow_partial(true)
434///   .with_obj_paths(["Device.Foo.1.", "Device.Bar.2"])
435///   .build();
436/// rusp::msg_builder()
437///   .with_msg_id("Foo")
438///   .with_body(body)
439///   .build()
440/// # "#;
441/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
442/// # assert!(!msg.is_error());
443/// # assert!(msg.is_request());
444/// # assert!(!msg.is_response());
445/// ```
446#[export_module]
447pub mod rhai_rusp_delete {
448    use usp_builder::DeleteBuilder;
449
450    /// Sets up a new USP `DeleteBuilder`
451    #[must_use]
452    pub const fn delete_builder() -> DeleteBuilder {
453        DeleteBuilder::new()
454    }
455
456    #[rhai_fn(global)]
457    #[must_use]
458    pub const fn with_allow_partial(builder: DeleteBuilder, allow_partial: bool) -> DeleteBuilder {
459        builder.with_allow_partial(allow_partial)
460    }
461
462    #[rhai_fn(global)]
463    #[must_use]
464    pub fn with_obj_paths(builder: DeleteBuilder, obj_paths: Array) -> DeleteBuilder {
465        builder.with_obj_paths(obj_paths.into_iter().map(Dynamic::cast).collect())
466    }
467
468    /// Turns the builder into a [`Body`] structure
469    ///
470    /// # Errors
471    ///
472    /// This function will return `Err` if the provided `builder` was set up with incomplete or
473    /// incorrect data.
474    #[rhai_fn(global, return_raw)]
475    pub fn build(builder: DeleteBuilder) -> Result<Body, Box<EvalAltResult>> {
476        Ok(builder.build().map_err(|e| e.to_string())?)
477    }
478}
479
480/// Supply Rusp DeleteResp Message functionality
481/// ```
482/// // Rhai script
483/// # let script = r#"
484/// let deleted_objs = [
485///   rusp::deleteresp_oper_failure("Foo", 7004, ""),
486///   rusp::deleteresp_oper_success("Foo.Bar.", ["Foo.Bar.1", "Foo.Bar.2."], [["Foo.Bar.3.", 7004, ""]])
487/// ];
488/// let body = rusp::deleteresp_builder()
489///   .with_deleted_obj_results(deleted_objs)
490///   .build();
491/// rusp::msg_builder()
492///   .with_msg_id("Foo")
493///   .with_body(body)
494///   .build()
495/// # "#;
496/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
497/// # assert!(!msg.is_error());
498/// # assert!(!msg.is_request());
499/// # assert!(msg.is_response());
500/// ```
501#[export_module]
502pub mod rhai_rusp_deleteresp {
503    use usp_builder::{
504        DeleteRespBuilder, DeleteRespUnaffectedPathError, DeletedObjectResultsBuilder,
505    };
506
507    /// Sets up a new USP `DeleteRespBuilder`
508    #[must_use]
509    pub const fn deleteresp_builder() -> DeleteRespBuilder {
510        DeleteRespBuilder::new()
511    }
512
513    #[rhai_fn(global)]
514    #[must_use]
515    pub fn with_deleted_obj_results(
516        builder: DeleteRespBuilder,
517        deleted_obj_results: Array,
518    ) -> DeleteRespBuilder {
519        let deleted_obj_results = deleted_obj_results.into_iter().map(Dynamic::cast).collect();
520        builder.with_deleted_obj_results(deleted_obj_results)
521    }
522
523    #[rhai_fn(global)]
524    #[must_use]
525    pub fn deleteresp_oper_failure(
526        requested_path: &str,
527        err_code: i64,
528        err_msg: &str,
529    ) -> DeletedObjectResultsBuilder {
530        DeletedObjectResultsBuilder::new(requested_path.into()).set_failure(
531            u32::try_from(err_code).unwrap_or(7003),
532            (!err_msg.is_empty()).then_some(err_msg.into()),
533        )
534    }
535
536    /// # Errors
537    ///
538    /// This function will return `Err` if the provided `unaffected_path_errs` cannot be converted
539    /// into an array of type `(String, u32, String)` or `affected_paths` cannot be converted into
540    /// an array of type `String`.
541    #[rhai_fn(global, return_raw)]
542    pub fn deleteresp_oper_success(
543        requested_path: &str,
544        affected_paths: Array,
545        unaffected_path_errs: Array,
546    ) -> Result<DeletedObjectResultsBuilder, Box<EvalAltResult>> {
547        let affected_paths = affected_paths
548            .into_iter()
549            .map(|p| {
550                p.try_cast::<String>()
551                    .ok_or_else(|| "Expected to have an array of Strings".into())
552            })
553            .collect::<Result<Vec<String>, Box<EvalAltResult>>>()?;
554
555        let unaffected_path_errs = unaffected_path_errs
556            .into_iter()
557            .map(|p| {
558                let el = p.try_cast::<Array>()
559                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, err_code: u32, err_msg: &str]".to_string())?;
560                let el0 = el.first()
561                    .and_then(|el| el.clone().try_cast::<String>())
562                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
563                let el1 = el.get(1)
564                    .and_then(|el| el.clone().try_cast::<i64>())
565                    .ok_or_else(|| "err_code (#2) needs to be a u32".to_string())?;
566                let el2 = el.get(2)
567                    .and_then(|el| el.clone().try_cast::<String>())
568                    .ok_or_else(|| "err_msg (#3) needs to be a string".to_string())?;
569
570                    Ok(DeleteRespUnaffectedPathError{unaffected_path: el0, err_code: u32::try_from(el1).unwrap_or(7003), err_msg: el2 })
571            })
572            .collect::<Result<Vec<DeleteRespUnaffectedPathError>, Box<EvalAltResult>>>()?;
573
574        Ok(DeletedObjectResultsBuilder::new(requested_path.into())
575            .set_success(affected_paths, unaffected_path_errs))
576    }
577
578    /// Turns the builder into a [`Body`] structure
579    ///
580    /// # Errors
581    ///
582    /// This function will return `Err` if the provided `builder` was set up with incomplete or
583    /// incorrect data.
584    #[rhai_fn(global, return_raw)]
585    pub fn build(builder: DeleteRespBuilder) -> Result<Body, Box<EvalAltResult>> {
586        Ok(builder.build().map_err(|e| e.to_string())?)
587    }
588}
589
590/// Supply Rusp Deregister Message functionality
591/// ```
592/// // Rhai script
593/// # let script = r#"
594/// let body = rusp::deregister_builder()
595///   .with_req_paths(["Device.Foo.", "Device.Bar."])
596///   .build();
597/// rusp::msg_builder()
598///   .with_msg_id("Foo")
599///   .with_body(body)
600///   .build()
601/// # "#;
602/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
603/// # assert!(!msg.is_error());
604/// # assert!(msg.is_request());
605/// # assert!(!msg.is_response());
606/// ```
607#[export_module]
608pub mod rhai_rusp_deregister {
609    use usp_builder::DeregisterBuilder;
610
611    /// Sets up a new USP `DeregisterBuilder`
612    #[must_use]
613    pub const fn deregister_builder() -> DeregisterBuilder {
614        DeregisterBuilder::new()
615    }
616
617    #[rhai_fn(global)]
618    #[must_use]
619    pub fn with_req_paths(builder: DeregisterBuilder, paths: Array) -> DeregisterBuilder {
620        builder.with_paths(paths.into_iter().map(Dynamic::cast).collect())
621    }
622
623    /// Turns the builder into a [`Body`] structure
624    ///
625    /// # Errors
626    ///
627    /// This function will return `Err` if the provided `builder` was set up with incomplete or
628    /// incorrect data.
629    #[rhai_fn(global, return_raw)]
630    pub fn build(builder: DeregisterBuilder) -> Result<Body, Box<EvalAltResult>> {
631        Ok(builder.build().map_err(|e| e.to_string())?)
632    }
633}
634
635/// Supply Rusp DeregistertResp Message functionality
636/// ```
637/// // Rhai script
638/// # let script = r#"
639/// let regpathres = [];
640/// regpathres += rusp::deregistered_path_result_builder("Device.")
641///   .set_failure(7002, "Look, a fancy error");
642/// regpathres += rusp::deregistered_path_result_builder("Device.")
643///   .set_success(["Device.Foo."]);
644/// let body = rusp::deregisterresp_builder()
645///   .with_deregistered_path_results(regpathres)
646///   .build();
647/// rusp::msg_builder()
648///   .with_msg_id("Foo")
649///   .with_body(body)
650///   .build()
651/// # "#;
652/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
653/// # assert!(!msg.is_error());
654/// # assert!(!msg.is_request());
655/// # assert!(msg.is_response());
656/// ```
657#[export_module]
658pub mod rhai_rusp_deregisterresp {
659    use usp_builder::{DeregisterRespBuilder, DeregisteredPathResultBuilder};
660
661    /// Sets up a new USP `DeregisterRespBuilder`
662    #[must_use]
663    pub const fn deregisterresp_builder() -> DeregisterRespBuilder {
664        DeregisterRespBuilder::new()
665    }
666
667    #[rhai_fn(global)]
668    #[must_use]
669    pub fn with_deregistered_path_results(
670        builder: DeregisterRespBuilder,
671        deregistered_path_results: Array,
672    ) -> DeregisterRespBuilder {
673        builder.with_deregistered_path_results(
674            deregistered_path_results
675                .into_iter()
676                .map(Dynamic::cast)
677                .collect(),
678        )
679    }
680
681    /// Turns the builder into a [`Body`] structure
682    ///
683    /// # Errors
684    ///
685    /// This function will return `Err` if the provided `builder` was set up with incomplete or
686    /// incorrect data.
687    #[rhai_fn(global, return_raw)]
688    pub fn build(builder: DeregisterRespBuilder) -> Result<Body, Box<EvalAltResult>> {
689        Ok(builder.build().map_err(|e| e.to_string())?)
690    }
691
692    #[must_use]
693    pub fn deregistered_path_result_builder(requested_path: &str) -> DeregisteredPathResultBuilder {
694        DeregisteredPathResultBuilder::new(requested_path.into())
695    }
696
697    #[rhai_fn(global, name = "set_failure")]
698    #[must_use]
699    pub fn deregisterresp_set_failure(
700        builder: DeregisteredPathResultBuilder,
701        err_code: i64,
702        err_msg: &str,
703    ) -> DeregisteredPathResultBuilder {
704        builder.set_failure(
705            u32::try_from(err_code).unwrap_or(7003),
706            (!err_msg.is_empty()).then_some(err_msg.into()),
707        )
708    }
709
710    #[rhai_fn(global, name = "set_success")]
711    #[must_use]
712    pub fn deregisterresp_set_success(
713        builder: DeregisteredPathResultBuilder,
714        deregistered_path: Array,
715    ) -> DeregisteredPathResultBuilder {
716        builder.set_success(deregistered_path.into_iter().map(Dynamic::cast).collect())
717    }
718}
719
720/// Supply Rusp Register Message functionality
721/// ```
722/// // Rhai script
723/// # let script = r#"
724/// let body = rusp::register_builder()
725///   .with_allow_partial(false)
726///   .with_reg_paths(["Device.Foo.", "Device.Bar."])
727///   .build();
728/// rusp::msg_builder()
729///   .with_msg_id("Foo")
730///   .with_body(body)
731///   .build()
732/// # "#;
733/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
734/// # assert!(!msg.is_error());
735/// # assert!(msg.is_request());
736/// # assert!(!msg.is_response());
737/// ```
738#[export_module]
739pub mod rhai_rusp_register {
740    use usp_builder::RegisterBuilder;
741
742    /// Sets up a new USP `RegisterBuilder`
743    #[must_use]
744    pub const fn register_builder() -> RegisterBuilder {
745        RegisterBuilder::new()
746    }
747
748    #[rhai_fn(global)]
749    #[must_use]
750    pub const fn with_allow_partial(
751        builder: RegisterBuilder,
752        allow_partial: bool,
753    ) -> RegisterBuilder {
754        builder.with_allow_partial(allow_partial)
755    }
756
757    #[rhai_fn(global)]
758    #[must_use]
759    pub fn with_reg_paths(builder: RegisterBuilder, req_paths: Array) -> RegisterBuilder {
760        builder.with_reg_paths(req_paths.into_iter().map(Dynamic::cast).collect())
761    }
762
763    /// Turns the builder into a [`Body`] structure
764    ///
765    /// # Errors
766    ///
767    /// This function will return `Err` if the provided `builder` was set up with incomplete or
768    /// incorrect data.
769    #[rhai_fn(global, return_raw)]
770    pub fn build(builder: RegisterBuilder) -> Result<Body, Box<EvalAltResult>> {
771        Ok(builder.build().map_err(|e| e.to_string())?)
772    }
773}
774
775/// Supply Rusp RegisterResp Message functionality
776/// ```
777/// // Rhai script
778/// # let script = r#"
779/// let regpathres = [];
780/// regpathres += rusp::registered_path_result_builder("Device.")
781///   .set_failure(7002, "Look, a fancy error");
782/// regpathres += rusp::registered_path_result_builder("Device.")
783///   .set_success("Device.Foo.");
784/// let body = rusp::registerresp_builder()
785///   .with_registered_path_results(regpathres)
786///   .build();
787/// rusp::msg_builder()
788///   .with_msg_id("Foo")
789///   .with_body(body)
790///   .build()
791/// # "#;
792/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
793/// # assert!(!msg.is_error());
794/// # assert!(!msg.is_request());
795/// # assert!(msg.is_response());
796/// ```
797#[export_module]
798pub mod rhai_rusp_registerresp {
799    use usp_builder::{RegisterRespBuilder, RegisteredPathResultBuilder};
800
801    /// Sets up a new USP `RegisterRespBuilder`
802    #[must_use]
803    pub const fn registerresp_builder() -> RegisterRespBuilder {
804        RegisterRespBuilder::new()
805    }
806
807    #[rhai_fn(global)]
808    #[must_use]
809    pub fn with_registered_path_results(
810        builder: RegisterRespBuilder,
811        registered_path_results: Array,
812    ) -> RegisterRespBuilder {
813        builder.with_registered_path_results(
814            registered_path_results
815                .into_iter()
816                .map(Dynamic::cast)
817                .collect(),
818        )
819    }
820
821    /// Turns the builder into a [`Body`] structure
822    ///
823    /// # Errors
824    ///
825    /// This function will return `Err` if the provided `builder` was set up with incomplete or
826    /// incorrect data.
827    #[rhai_fn(global, return_raw)]
828    pub fn build(builder: RegisterRespBuilder) -> Result<Body, Box<EvalAltResult>> {
829        Ok(builder.build().map_err(|e| e.to_string())?)
830    }
831
832    #[must_use]
833    pub fn registered_path_result_builder(requested_path: &str) -> RegisteredPathResultBuilder {
834        RegisteredPathResultBuilder::new(requested_path.into())
835    }
836
837    #[rhai_fn(global, name = "set_failure")]
838    #[must_use]
839    pub fn registerresp_set_failure(
840        builder: RegisteredPathResultBuilder,
841        err_code: i64,
842        err_msg: &str,
843    ) -> RegisteredPathResultBuilder {
844        builder.set_failure(
845            u32::try_from(err_code).unwrap_or(7003),
846            (!err_msg.is_empty()).then_some(err_msg.into()),
847        )
848    }
849
850    #[rhai_fn(global, name = "set_success")]
851    #[must_use]
852    pub fn registerresp_set_success(
853        builder: RegisteredPathResultBuilder,
854        registered_path: &str,
855    ) -> RegisteredPathResultBuilder {
856        builder.set_success(registered_path.into())
857    }
858}
859
860/// Supply Rusp Set Message functionality
861/// ```
862/// // Rhai script
863/// # let script = r#"
864/// let update_obj = rusp::set_update_object_builder("Device.IP.Interface.")
865///   .with_param_settings([["Foo", "Bar", true],["Whee", "What?", false]]);
866/// let body = rusp::set_builder()
867///   .with_allow_partial(true)
868///   .with_update_objs([update_obj])
869///   .build();
870/// rusp::msg_builder()
871///   .with_msg_id("Foo")
872///   .with_body(body)
873///   .build()
874/// # "#;
875/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
876/// # assert!(!msg.is_error());
877/// # assert!(msg.is_request());
878/// # assert!(!msg.is_response());
879/// ```
880#[export_module]
881pub mod rhai_rusp_set {
882    use usp_builder::{SetBuilder, UpdateObjectBuilder};
883
884    /// Sets up a new USP `SetBuilder`
885    #[must_use]
886    pub const fn set_builder() -> SetBuilder {
887        SetBuilder::new()
888    }
889
890    #[rhai_fn(global)]
891    #[must_use]
892    pub const fn with_allow_partial(builder: SetBuilder, allow_partial: bool) -> SetBuilder {
893        builder.with_allow_partial(allow_partial)
894    }
895
896    #[rhai_fn(global)]
897    #[must_use]
898    pub fn with_update_objs(builder: SetBuilder, create_objs: Array) -> SetBuilder {
899        builder.with_update_objs(create_objs.into_iter().map(Dynamic::cast).collect())
900    }
901
902    #[rhai_fn(global)]
903    #[must_use]
904    pub fn set_update_object_builder(obj_path: &str) -> UpdateObjectBuilder {
905        UpdateObjectBuilder::new(obj_path.into())
906    }
907
908    #[rhai_fn(global, return_raw)]
909    ///
910    /// # Errors
911    ///
912    /// This function will return `Err` if the provided `param_settings` cannot be converted into
913    /// an array of type `(String, String, bool)`.
914    pub fn with_param_settings(
915        mut builder: UpdateObjectBuilder,
916        param_settings: Array,
917    ) -> Result<UpdateObjectBuilder, Box<EvalAltResult>> {
918        let param_settings = param_settings
919            .into_iter()
920            .map(|p| {
921                let el = p.try_cast::<Array>()
922                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, value: &str, required: bool]".to_string())?;
923                let el0 = el.first()
924                    .and_then(|el| el.clone().try_cast::<String>())
925                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
926                let el1 = el.get(1)
927                    .and_then(|el| el.clone().try_cast::<String>())
928                    .ok_or_else(|| "value (#2) needs to be a string".to_string())?;
929                let el2 = el.get(2)
930                    .and_then(|el| el.clone().try_cast::<bool>())
931                    .ok_or_else(|| "required (#3) needs to be a bool".to_string())?;
932
933                Ok((el0, el1, el2))
934            })
935            .collect::<Result<Vec<(String, String, bool)>, Box<EvalAltResult>>>()?;
936        builder = builder.with_param_settings(param_settings);
937
938        Ok(builder)
939    }
940
941    /// Turns the builder into a [`Body`] structure
942    ///
943    /// # Errors
944    ///
945    /// This function will return `Err` if the provided `builder` was set up with incomplete or
946    /// incorrect data.
947    #[rhai_fn(global, return_raw)]
948    pub fn build(builder: SetBuilder) -> Result<Body, Box<EvalAltResult>> {
949        Ok(builder.build().map_err(|e| e.to_string())?)
950    }
951}
952
953/// Supply Rusp SetResp Message functionality
954/// ```
955/// // Rhai script
956/// # let script = r#"
957/// let failure = setresp_updated_instance_failure_builder("Foo.Bar.")
958///   .with_param_errs ([["Baz", 7002, ""]]);
959/// let updated_objs = [
960///   rusp::setresp_updated_obj_failure("Foo.Bar.", 0, "", [failure]),
961///   rusp::setresp_updated_obj_success("Foo", "Foo.Bar.1", [["Bar", 7004, ""]], #{"Foo": "Bar"})
962/// ];
963/// let body = rusp::setresp_builder()
964///   .with_updated_obj_results(updated_objs)
965///   .build();
966/// rusp::msg_builder()
967///   .with_msg_id("Foo")
968///   .with_body(body)
969///   .build()
970/// # "#;
971/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
972/// # assert!(!msg.is_error());
973/// # assert!(!msg.is_request());
974/// # assert!(msg.is_response());
975/// ```
976#[export_module]
977pub mod rhai_rusp_setresp {
978    use usp_builder::{
979        SetOperationStatus, SetOperationSuccessBuilder, SetRespBuilder, SetRespParameterError,
980        UpdatedInstanceFailureBuilder, UpdatedObjectResultsBuilder,
981    };
982
983    /// Sets up a new USP `SetRespBuilder`
984    #[must_use]
985    pub const fn setresp_builder() -> SetRespBuilder {
986        SetRespBuilder::new()
987    }
988
989    #[rhai_fn(global)]
990    #[must_use]
991    pub fn with_updated_obj_results(
992        builder: SetRespBuilder,
993        updated_obj_results: Array,
994    ) -> SetRespBuilder {
995        let updated_obj_results = updated_obj_results.into_iter().map(Dynamic::cast).collect();
996        builder.with_updated_obj_results(updated_obj_results)
997    }
998
999    #[rhai_fn(global)]
1000    #[must_use]
1001    pub fn setresp_updated_instance_failure_builder(
1002        affected_path: &str,
1003    ) -> UpdatedInstanceFailureBuilder {
1004        UpdatedInstanceFailureBuilder::new(affected_path.into())
1005    }
1006
1007    #[rhai_fn(global, return_raw)]
1008    ///
1009    /// # Errors
1010    ///
1011    /// This function will return `Err` if the provided `param_errs` cannot be converted into
1012    /// an array of type `(String, u32, String)`.
1013    pub fn with_param_errs(
1014        builder: UpdatedInstanceFailureBuilder,
1015        param_errs: Array,
1016    ) -> Result<UpdatedInstanceFailureBuilder, Box<EvalAltResult>> {
1017        let param_errs = param_errs
1018            .into_iter()
1019            .map(|p| {
1020                let el = p.try_cast::<Array>()
1021                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, err_code: u32, err_msg: &str]".to_string())?;
1022                let el0 = el.first()
1023                    .and_then(|el| el.clone().try_cast::<String>())
1024                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
1025                let el1 = el.get(1)
1026                    .and_then(|el| el.clone().try_cast::<i64>())
1027                    .ok_or_else(|| "err_code (#2) needs to be a u32".to_string())?;
1028                let el2 = el.get(2)
1029                    .and_then(|el| el.clone().try_cast::<String>())
1030                    .ok_or_else(|| "err_msg (#3) needs to be a string".to_string())?;
1031
1032                Ok(SetRespParameterError::new(el0, u32::try_from(el1).unwrap_or(7003), Some(el2)))
1033            })
1034            .collect::<Result<Vec<SetRespParameterError>, Box<EvalAltResult>>>()?;
1035        Ok(builder.with_param_errs(param_errs))
1036    }
1037
1038    #[rhai_fn(global)]
1039    #[must_use]
1040    pub fn setresp_updated_obj_failure(
1041        requested_path: &str,
1042        err_code: i64,
1043        err_msg: &str,
1044        updated_inst_failures: Array,
1045    ) -> UpdatedObjectResultsBuilder {
1046        let oper_status = SetOperationStatus::new().set_failure(
1047            u32::try_from(err_code).unwrap_or(7003),
1048            (!err_msg.is_empty()).then_some(err_msg.into()),
1049            updated_inst_failures
1050                .into_iter()
1051                .map(Dynamic::cast)
1052                .collect(),
1053        );
1054        UpdatedObjectResultsBuilder::new(requested_path.into(), oper_status)
1055    }
1056
1057    /// # Errors
1058    ///
1059    /// This function will return `Err` if the provided `param_errs` cannot be converted into
1060    /// an array of type `(String, u32, String)`.
1061    #[rhai_fn(global, return_raw)]
1062    pub fn setresp_updated_obj_success(
1063        requested_path: &str,
1064        affected_path: &str,
1065        param_errs: Array,
1066        updated_params: Map,
1067    ) -> Result<UpdatedObjectResultsBuilder, Box<EvalAltResult>> {
1068        let param_errs = param_errs
1069            .into_iter()
1070            .map(|p| {
1071                let el = p.try_cast::<Array>()
1072                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, err_code: u32, err_msg: &str]".to_string())?;
1073                let el0 = el.first()
1074                    .and_then(|el| el.clone().try_cast::<String>())
1075                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
1076                let el1 = el.get(1)
1077                    .and_then(|el| el.clone().try_cast::<i64>())
1078                    .ok_or_else(|| "err_code (#2) needs to be a u32".to_string())?;
1079                let el2 = el.get(2)
1080                    .and_then(|el| el.clone().try_cast::<String>())
1081                    .ok_or_else(|| "err_msg (#3) needs to be a string".to_string())?;
1082
1083                Ok(SetRespParameterError::new(el0, u32::try_from(el1).unwrap_or(7003), Some(el2)))
1084            })
1085            .collect::<Result<Vec<SetRespParameterError>, Box<EvalAltResult>>>()?;
1086
1087        let updated_params = updated_params
1088            .iter()
1089            .map(|(k, v)| (k.to_string(), v.to_string()))
1090            .collect();
1091
1092        Ok(UpdatedObjectResultsBuilder::new(
1093            requested_path.into(),
1094            SetOperationStatus::new().set_success(vec![SetOperationSuccessBuilder::new(
1095                affected_path.into(),
1096            )
1097            .with_updated_params(updated_params)
1098            .with_param_errs(param_errs)]),
1099        ))
1100    }
1101
1102    /// Turns the builder into a [`Body`] structure
1103    ///
1104    /// # Errors
1105    ///
1106    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1107    /// incorrect data.
1108    #[rhai_fn(global, return_raw)]
1109    pub fn build(builder: SetRespBuilder) -> Result<Body, Box<EvalAltResult>> {
1110        Ok(builder.build().map_err(|e| e.to_string())?)
1111    }
1112}
1113
1114/// Supply Rusp Error Message functionality
1115/// ```
1116/// // Rhai script
1117/// # let script = r#"
1118/// let body = rusp::error_builder()
1119///   .set_err(7002, "I don't know")
1120///   .with_param_errs([["Foo", 7002, ""]])
1121///   .build();
1122/// rusp::msg_builder()
1123///   .with_msg_id("Foo")
1124///   .with_body(body)
1125///   .build()
1126/// # "#;
1127/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1128/// # assert!(msg.is_error());
1129/// # assert!(!msg.is_request());
1130/// # assert!(!msg.is_response());
1131/// ```
1132#[export_module]
1133pub mod rhai_rusp_error {
1134    use usp_builder::ErrorBuilder;
1135
1136    /// Sets up a new USP `ErrorBuilder`
1137    #[must_use]
1138    pub const fn error_builder() -> ErrorBuilder {
1139        ErrorBuilder::new()
1140    }
1141
1142    #[rhai_fn(global)]
1143    #[must_use]
1144    pub fn set_err(builder: ErrorBuilder, err_code: i64, err_msg: &str) -> ErrorBuilder {
1145        builder.set_err(
1146            u32::try_from(err_code).unwrap_or(7003),
1147            (!err_msg.is_empty()).then_some(err_msg.into()),
1148        )
1149    }
1150
1151    /// # Errors
1152    ///
1153    /// This function will return `Err` if the provided `param_errs` cannot be converted into
1154    /// an array of type `(String, u32, String)`.
1155    #[rhai_fn(global, return_raw)]
1156    pub fn with_param_errs(
1157        builder: ErrorBuilder,
1158        param_errs: Array,
1159    ) -> Result<ErrorBuilder, Box<EvalAltResult>> {
1160        let param_errs = param_errs
1161            .into_iter()
1162            .map(|p| {
1163                let el = p.try_cast::<Array>()
1164                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, err_code: u32, err_msg: &str]".to_string())?;
1165                let el0 = el.first()
1166                    .and_then(|el| el.clone().try_cast::<String>())
1167                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
1168                let el1 = el.get(1)
1169                    .and_then(|el| el.clone().try_cast::<i64>())
1170                    .ok_or_else(|| "err_code (#2) needs to be a u32".to_string())?;
1171                let el2 = el.get(2)
1172                    .and_then(|el| el.clone().try_cast::<String>())
1173                    .ok_or_else(|| "err_msg (#3) needs to be a string".to_string())?;
1174
1175                Ok((el0, u32::try_from(el1).unwrap_or(7003), el2))
1176            })
1177            .collect::<Result<Vec<_>, Box<EvalAltResult>>>()?;
1178
1179        Ok(builder.with_param_errs(param_errs))
1180    }
1181
1182    /// Turns the builder into a [`Body`] structure
1183    ///
1184    /// # Errors
1185    ///
1186    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1187    /// incorrect data.
1188    #[rhai_fn(global, return_raw)]
1189    pub fn build(builder: ErrorBuilder) -> Result<Body, Box<EvalAltResult>> {
1190        Ok(builder.build().map_err(|e| e.to_string())?)
1191    }
1192}
1193
1194/// Supply Rusp Get Message functionality
1195/// ```
1196/// // Rhai script
1197/// # let script = r#"
1198/// let body = rusp::get_builder()
1199///   .with_params(["Device."])
1200///   .with_max_depth(1)
1201///   .build();
1202/// rusp::msg_builder()
1203///   .with_msg_id("Foo")
1204///   .with_body(body)
1205///   .build()
1206/// # "#;
1207/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1208/// # assert!(!msg.is_error());
1209/// # assert!(msg.is_request());
1210/// # assert!(!msg.is_response());
1211/// ```
1212#[export_module]
1213pub mod rhai_rusp_get {
1214    use usp_builder::GetBuilder;
1215
1216    /// Sets up a new USP `GetBuilder`
1217    #[must_use]
1218    pub const fn get_builder() -> GetBuilder {
1219        GetBuilder::new()
1220    }
1221
1222    #[rhai_fn(global)]
1223    #[must_use]
1224    pub fn with_max_depth(builder: GetBuilder, max_depth: i64) -> GetBuilder {
1225        builder.with_max_depth(u32::try_from(max_depth).unwrap_or(0))
1226    }
1227
1228    #[rhai_fn(global)]
1229    #[must_use]
1230    pub fn with_params(builder: GetBuilder, params: Array) -> GetBuilder {
1231        builder.with_params(params.into_iter().map(Dynamic::cast).collect())
1232    }
1233
1234    /// Turns the builder into a [`Body`] structure
1235    ///
1236    /// # Errors
1237    ///
1238    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1239    /// incorrect data.
1240    #[rhai_fn(global, return_raw)]
1241    pub fn build(builder: GetBuilder) -> Result<Body, Box<EvalAltResult>> {
1242        Ok(builder.build().map_err(|e| e.to_string())?)
1243    }
1244}
1245
1246/// Supply Rusp GetResp Message functionality
1247/// ```
1248/// // Rhai script
1249/// # let script = r#"
1250/// let respathres = [];
1251/// respathres += rusp::get_res_path_result_builder("Device.")
1252///   .with_result_params(#{"Foo": "Bar"});
1253/// let reqpathres = [];
1254/// reqpathres += rusp::req_path_result_builder("Device.")
1255///   .set_err(7002, "Look, a fancy error")
1256///   .with_res_path_result(respathres);
1257/// let body = rusp::getresp_builder()
1258///   .with_req_path_results(reqpathres)
1259///   .build();
1260/// rusp::msg_builder()
1261///   .with_msg_id("Foo")
1262///   .with_body(body)
1263///   .build()
1264/// # "#;
1265/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1266/// # assert!(!msg.is_error());
1267/// # assert!(!msg.is_request());
1268/// # assert!(msg.is_response());
1269/// ```
1270#[export_module]
1271pub mod rhai_rusp_getresp {
1272    use usp_builder::{GetReqPathResultBuilder, GetRespBuilder, ResolvedPathResultBuilder};
1273
1274    /// Sets up a new USP `GetRespBuilder`
1275    #[must_use]
1276    pub const fn getresp_builder() -> GetRespBuilder {
1277        GetRespBuilder::new()
1278    }
1279
1280    #[rhai_fn(global)]
1281    #[must_use]
1282    pub fn with_req_path_results(
1283        builder: GetRespBuilder,
1284        req_path_results: Array,
1285    ) -> GetRespBuilder {
1286        builder.with_req_path_results(req_path_results.into_iter().map(Dynamic::cast).collect())
1287    }
1288
1289    /// Turns the builder into a [`Body`] structure
1290    ///
1291    /// # Errors
1292    ///
1293    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1294    /// incorrect data.
1295    #[rhai_fn(global, return_raw)]
1296    pub fn build(builder: GetRespBuilder) -> Result<Body, Box<EvalAltResult>> {
1297        Ok(builder.build().map_err(|e| e.to_string())?)
1298    }
1299
1300    #[must_use]
1301    pub fn req_path_result_builder(requested_path: &str) -> GetReqPathResultBuilder {
1302        GetReqPathResultBuilder::new(requested_path.into())
1303    }
1304
1305    #[rhai_fn(global)]
1306    #[must_use]
1307    pub fn set_err(
1308        builder: GetReqPathResultBuilder,
1309        err_code: i64,
1310        err_msg: &str,
1311    ) -> GetReqPathResultBuilder {
1312        builder.set_err(
1313            u32::try_from(err_code).unwrap_or(7003),
1314            (!err_msg.is_empty()).then_some(err_msg.into()),
1315        )
1316    }
1317
1318    #[rhai_fn(global)]
1319    #[must_use]
1320    pub fn with_res_path_result(
1321        builder: GetReqPathResultBuilder,
1322        resolved_path_results: Array,
1323    ) -> GetReqPathResultBuilder {
1324        builder.with_res_path_results(
1325            resolved_path_results
1326                .into_iter()
1327                .map(Dynamic::cast)
1328                .collect(),
1329        )
1330    }
1331
1332    #[must_use]
1333    pub fn get_res_path_result_builder(resolved_path: &str) -> ResolvedPathResultBuilder {
1334        ResolvedPathResultBuilder::new(resolved_path.into())
1335    }
1336
1337    #[rhai_fn(global)]
1338    #[must_use]
1339    pub fn with_result_params(
1340        builder: ResolvedPathResultBuilder,
1341        result_params: Map,
1342    ) -> ResolvedPathResultBuilder {
1343        let result_params = result_params
1344            .iter()
1345            .map(|(k, v)| (k.to_string(), v.to_string()))
1346            .collect();
1347        builder.with_result_params(result_params)
1348    }
1349}
1350
1351/// Supply Rusp GetSupportedDM Message functionality
1352/// ```
1353/// // Rhai script
1354/// # let script = r#"
1355/// let body = rusp::getsupporteddm_builder()
1356///   .with_obj_paths(["Device.", "Device.DeviceInfo."])
1357///   .with_first_level_only(true)
1358///   .with_return_commands(false)
1359///   .with_return_events(false)
1360///   .with_return_params(false)
1361///   .with_return_unique_key_sets(true)
1362///   .build();
1363/// rusp::msg_builder()
1364///   .with_msg_id("Foo")
1365///   .with_body(body)
1366///   .build()
1367/// # "#;
1368/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1369/// # assert!(!msg.is_error());
1370/// # assert!(msg.is_request());
1371/// # assert!(!msg.is_response());
1372/// ```
1373#[export_module]
1374pub mod rhai_rusp_getsupporteddm {
1375    use usp_builder::GetSupportedDMBuilder;
1376
1377    /// Sets up a new USP `GetSupportedDMBuilder`
1378    #[must_use]
1379    pub const fn getsupporteddm_builder() -> GetSupportedDMBuilder {
1380        GetSupportedDMBuilder::new()
1381    }
1382
1383    #[rhai_fn(global)]
1384    #[must_use]
1385    pub const fn with_first_level_only(
1386        builder: GetSupportedDMBuilder,
1387        first_level_only: bool,
1388    ) -> GetSupportedDMBuilder {
1389        builder.with_first_level_only(first_level_only)
1390    }
1391
1392    #[rhai_fn(global)]
1393    #[must_use]
1394    pub fn with_obj_paths(
1395        builder: GetSupportedDMBuilder,
1396        obj_paths: Array,
1397    ) -> GetSupportedDMBuilder {
1398        builder.with_obj_paths(obj_paths.into_iter().map(Dynamic::cast).collect())
1399    }
1400
1401    #[rhai_fn(global)]
1402    #[must_use]
1403    pub const fn with_return_commands(
1404        builder: GetSupportedDMBuilder,
1405        return_commands: bool,
1406    ) -> GetSupportedDMBuilder {
1407        builder.with_return_commands(return_commands)
1408    }
1409
1410    #[rhai_fn(global)]
1411    #[must_use]
1412    pub const fn with_return_events(
1413        builder: GetSupportedDMBuilder,
1414        return_events: bool,
1415    ) -> GetSupportedDMBuilder {
1416        builder.with_return_events(return_events)
1417    }
1418
1419    #[rhai_fn(global)]
1420    #[must_use]
1421    pub const fn with_return_params(
1422        builder: GetSupportedDMBuilder,
1423        return_params: bool,
1424    ) -> GetSupportedDMBuilder {
1425        builder.with_return_params(return_params)
1426    }
1427
1428    #[rhai_fn(global)]
1429    #[must_use]
1430    pub const fn with_return_unique_key_sets(
1431        builder: GetSupportedDMBuilder,
1432        return_unique_key_sets: bool,
1433    ) -> GetSupportedDMBuilder {
1434        builder.with_return_unique_key_sets(return_unique_key_sets)
1435    }
1436
1437    /// Turns the builder into a [`Body`] structure
1438    ///
1439    /// # Errors
1440    ///
1441    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1442    /// incorrect data.
1443    #[rhai_fn(global, return_raw)]
1444    pub fn build(builder: GetSupportedDMBuilder) -> Result<Body, Box<EvalAltResult>> {
1445        Ok(builder.build().map_err(|e| e.to_string())?)
1446    }
1447}
1448
1449/// Supply Rusp GetSupportedDMResp Message functionality
1450/// ```
1451/// // Rhai script
1452/// # let script = r#"
1453/// let command = rusp::getsupporteddmresp_command_result_builder("Foo()")
1454///   .with_input_arg_names(["Foo", "Bar", "Baz"])
1455///   .with_output_arg_names(["Bam"])
1456///   .set_sync();
1457/// let event = rusp::getsupporteddmresp_event_result_builder("Foo!")
1458///   .with_arg_names(["Foo", "Bar", "Baz"]);
1459/// let param = rusp::getsupporteddmresp_param_result_builder("Foo")
1460///   .set_type_boolean()
1461///   .set_value_change_allowed()
1462///   .set_access_read_write();
1463/// let req_obj1 = rusp::getsupporteddm_req_obj_result_builder("Device.")
1464///   .set_err(7005, "");
1465/// let supported_obj = rusp::getsupporteddmresp_supported_obj_result_builder("Device.DeviceInfo.")
1466///   .with_is_multi_instance(false)
1467///   .set_access_add_delete()
1468///   .with_supported_commands([command])
1469///   .with_supported_events([event])
1470///   .with_supported_params([param])
1471///   .with_divergent_paths(["Device.DeviceInfo.Foo.1.", "Device.DeviceInfo.Foo.2."])
1472///   .with_unique_key_sets([["Foo", "Bar"], ["Baz"]]);
1473/// let req_obj2 = rusp::getsupporteddm_req_obj_result_builder("Device.DeviceInfo.")
1474///   .with_data_model_inst_uri("urn:broadband-forum-org:tr-181-2-17-0-usp")
1475///   .with_supported_objs([supported_obj]);
1476/// let body = rusp::getsupporteddmresp_builder()
1477///   .with_req_obj_results([req_obj1, req_obj2])
1478///   .build();
1479/// rusp::msg_builder()
1480///   .with_msg_id("Foo")
1481///   .with_body(body)
1482///   .build()
1483/// # "#;
1484/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1485/// # assert!(!msg.is_error());
1486/// # assert!(!msg.is_request());
1487/// # assert!(msg.is_response());
1488/// ```
1489#[export_module]
1490pub mod rhai_rusp_getsupporteddmresp {
1491    use usp_builder::{
1492        GSDMCommandResult, GSDMEventResult, GSDMParamResult, GSDMReqObjectResultBuilder,
1493        GSDMSupportedObjectResultBuilder, GetSupportedDMRespBuilder,
1494    };
1495
1496    /// Sets up a new USP `GetSupportedDMRespBuilder`
1497    #[must_use]
1498    pub const fn getsupporteddmresp_builder() -> GetSupportedDMRespBuilder {
1499        GetSupportedDMRespBuilder::new()
1500    }
1501
1502    #[rhai_fn(global)]
1503    #[must_use]
1504    pub fn with_req_obj_results(
1505        builder: GetSupportedDMRespBuilder,
1506        req_obj_results: Array,
1507    ) -> GetSupportedDMRespBuilder {
1508        builder.with_req_obj_results(req_obj_results.into_iter().map(Dynamic::cast).collect())
1509    }
1510
1511    /// Turns the builder into a [`Body`] structure
1512    ///
1513    /// # Errors
1514    ///
1515    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1516    /// incorrect data.
1517    #[rhai_fn(global, return_raw)]
1518    pub fn build(builder: GetSupportedDMRespBuilder) -> Result<Body, Box<EvalAltResult>> {
1519        Ok(builder.build().map_err(|e| e.to_string())?)
1520    }
1521
1522    #[must_use]
1523    pub fn getsupporteddm_req_obj_result_builder(req_obj_path: &str) -> GSDMReqObjectResultBuilder {
1524        GSDMReqObjectResultBuilder::new(req_obj_path.into())
1525    }
1526
1527    #[rhai_fn(global)]
1528    #[must_use]
1529    pub fn set_err(
1530        builder: GSDMReqObjectResultBuilder,
1531        err_code: i64,
1532        err_msg: &str,
1533    ) -> GSDMReqObjectResultBuilder {
1534        builder.set_err(
1535            u32::try_from(err_code).unwrap_or(7003),
1536            (!err_msg.is_empty()).then_some(err_msg.into()),
1537        )
1538    }
1539
1540    #[rhai_fn(global)]
1541    #[must_use]
1542    pub fn with_data_model_inst_uri(
1543        builder: GSDMReqObjectResultBuilder,
1544        data_model_inst_uri: &str,
1545    ) -> GSDMReqObjectResultBuilder {
1546        builder.with_data_model_inst_uri(data_model_inst_uri.into())
1547    }
1548
1549    #[rhai_fn(global)]
1550    #[must_use]
1551    pub fn with_supported_objs(
1552        builder: GSDMReqObjectResultBuilder,
1553        supported_objs: Array,
1554    ) -> GSDMReqObjectResultBuilder {
1555        builder.with_supported_objs(supported_objs.into_iter().map(Dynamic::cast).collect())
1556    }
1557
1558    #[must_use]
1559    pub fn getsupporteddmresp_supported_obj_result_builder(
1560        req_obj_path: &str,
1561    ) -> GSDMSupportedObjectResultBuilder {
1562        GSDMSupportedObjectResultBuilder::new(req_obj_path.into())
1563    }
1564
1565    #[rhai_fn(global)]
1566    #[must_use]
1567    pub const fn with_is_multi_instance(
1568        builder: GSDMSupportedObjectResultBuilder,
1569        is_multi_instance: bool,
1570    ) -> GSDMSupportedObjectResultBuilder {
1571        builder.with_is_multi_instance(is_multi_instance)
1572    }
1573
1574    #[rhai_fn(global)]
1575    #[must_use]
1576    pub const fn set_access_add_only(
1577        builder: GSDMSupportedObjectResultBuilder,
1578    ) -> GSDMSupportedObjectResultBuilder {
1579        builder.set_access_add_only()
1580    }
1581
1582    #[rhai_fn(global)]
1583    #[must_use]
1584    pub const fn set_access_delete_only(
1585        builder: GSDMSupportedObjectResultBuilder,
1586    ) -> GSDMSupportedObjectResultBuilder {
1587        builder.set_access_delete_only()
1588    }
1589
1590    #[rhai_fn(global, name = "set_access_read_only")]
1591    #[must_use]
1592    pub const fn obj_set_access_read_only(
1593        builder: GSDMSupportedObjectResultBuilder,
1594    ) -> GSDMSupportedObjectResultBuilder {
1595        builder.set_access_read_only()
1596    }
1597
1598    #[rhai_fn(global)]
1599    #[must_use]
1600    pub const fn set_access_add_delete(
1601        builder: GSDMSupportedObjectResultBuilder,
1602    ) -> GSDMSupportedObjectResultBuilder {
1603        builder.set_access_add_delete()
1604    }
1605
1606    #[rhai_fn(global)]
1607    #[must_use]
1608    pub fn with_supported_commands(
1609        builder: GSDMSupportedObjectResultBuilder,
1610        supported_commands: Array,
1611    ) -> GSDMSupportedObjectResultBuilder {
1612        builder.with_supported_commands(supported_commands.into_iter().map(Dynamic::cast).collect())
1613    }
1614
1615    #[rhai_fn(global)]
1616    #[must_use]
1617    pub fn with_supported_events(
1618        builder: GSDMSupportedObjectResultBuilder,
1619        supported_events: Array,
1620    ) -> GSDMSupportedObjectResultBuilder {
1621        builder.with_supported_events(supported_events.into_iter().map(Dynamic::cast).collect())
1622    }
1623
1624    #[rhai_fn(global)]
1625    #[must_use]
1626    pub fn with_supported_params(
1627        builder: GSDMSupportedObjectResultBuilder,
1628        supported_params: Array,
1629    ) -> GSDMSupportedObjectResultBuilder {
1630        builder.with_supported_params(supported_params.into_iter().map(Dynamic::cast).collect())
1631    }
1632
1633    #[rhai_fn(global)]
1634    #[must_use]
1635    pub fn with_divergent_paths(
1636        builder: GSDMSupportedObjectResultBuilder,
1637        divergent_paths: Array,
1638    ) -> GSDMSupportedObjectResultBuilder {
1639        builder.with_divergent_paths(divergent_paths.into_iter().map(Dynamic::cast).collect())
1640    }
1641
1642    /// # Errors
1643    ///
1644    /// This function will return `Err` if the provided `unique_key_sets` cannot be converted into
1645    /// an array of type `String`.
1646    #[rhai_fn(global, return_raw)]
1647    pub fn with_unique_key_sets(
1648        builder: GSDMSupportedObjectResultBuilder,
1649        unique_key_sets: Array,
1650    ) -> Result<GSDMSupportedObjectResultBuilder, Box<EvalAltResult>> {
1651        let unique_key_sets = unique_key_sets
1652            .into_iter()
1653            .map(|p| {
1654                p.try_cast::<Array>()
1655                    .ok_or_else(|| "Expected to have an array of arrays of string".to_string())?
1656                    .iter()
1657                    .map(|el| {
1658                        el.clone()
1659                            .try_cast::<String>()
1660                            .ok_or_else(|| "param needs to be a string".to_string())
1661                    })
1662                    .collect::<Result<Vec<String>, _>>()
1663            })
1664            .collect::<Result<Vec<Vec<String>>, _>>()?;
1665        Ok(builder.with_unique_key_sets(unique_key_sets))
1666    }
1667
1668    #[must_use]
1669    pub fn getsupporteddmresp_command_result_builder(command_name: &str) -> GSDMCommandResult {
1670        GSDMCommandResult::new(command_name.into())
1671    }
1672
1673    #[rhai_fn(global)]
1674    #[must_use]
1675    pub fn with_input_arg_names(
1676        builder: GSDMCommandResult,
1677        input_arg_names: Array,
1678    ) -> GSDMCommandResult {
1679        builder.with_input_arg_names(input_arg_names.into_iter().map(Dynamic::cast).collect())
1680    }
1681
1682    #[rhai_fn(global)]
1683    #[must_use]
1684    pub fn with_output_arg_names(
1685        builder: GSDMCommandResult,
1686        output_arg_names: Array,
1687    ) -> GSDMCommandResult {
1688        builder.with_output_arg_names(output_arg_names.into_iter().map(Dynamic::cast).collect())
1689    }
1690
1691    #[rhai_fn(global)]
1692    #[must_use]
1693    pub const fn set_sync(builder: GSDMCommandResult) -> GSDMCommandResult {
1694        builder.set_sync()
1695    }
1696
1697    #[rhai_fn(global)]
1698    #[must_use]
1699    pub const fn set_async(builder: GSDMCommandResult) -> GSDMCommandResult {
1700        builder.set_async()
1701    }
1702
1703    #[must_use]
1704    pub fn getsupporteddmresp_event_result_builder(event_name: &str) -> GSDMEventResult {
1705        GSDMEventResult::new(event_name.into())
1706    }
1707
1708    #[rhai_fn(global)]
1709    #[must_use]
1710    pub fn with_arg_names(builder: GSDMEventResult, input_arg_names: Array) -> GSDMEventResult {
1711        builder.with_arg_names(input_arg_names.into_iter().map(Dynamic::cast).collect())
1712    }
1713
1714    #[must_use]
1715    pub fn getsupporteddmresp_param_result_builder(param_name: &str) -> GSDMParamResult {
1716        GSDMParamResult::new(param_name.into())
1717    }
1718
1719    #[rhai_fn(global)]
1720    #[must_use]
1721    pub const fn set_access_read_only(builder: GSDMParamResult) -> GSDMParamResult {
1722        builder.set_access_read_only()
1723    }
1724
1725    #[rhai_fn(global)]
1726    #[must_use]
1727    pub const fn set_access_write_only(builder: GSDMParamResult) -> GSDMParamResult {
1728        builder.set_access_write_only()
1729    }
1730
1731    #[rhai_fn(global)]
1732    #[must_use]
1733    pub const fn set_access_read_write(builder: GSDMParamResult) -> GSDMParamResult {
1734        builder.set_access_read_write()
1735    }
1736
1737    #[rhai_fn(global)]
1738    #[must_use]
1739    pub const fn set_type_int(builder: GSDMParamResult) -> GSDMParamResult {
1740        builder.set_type_int()
1741    }
1742
1743    #[rhai_fn(global)]
1744    #[must_use]
1745    pub const fn set_type_unsigned_int(builder: GSDMParamResult) -> GSDMParamResult {
1746        builder.set_type_unsigned_int()
1747    }
1748
1749    #[rhai_fn(global)]
1750    #[must_use]
1751    pub const fn set_type_long(builder: GSDMParamResult) -> GSDMParamResult {
1752        builder.set_type_long()
1753    }
1754
1755    #[rhai_fn(global)]
1756    #[must_use]
1757    pub const fn set_type_unsigned_long(builder: GSDMParamResult) -> GSDMParamResult {
1758        builder.set_type_unsigned_long()
1759    }
1760
1761    #[rhai_fn(global)]
1762    #[must_use]
1763    pub const fn set_type_string(builder: GSDMParamResult) -> GSDMParamResult {
1764        builder.set_type_string()
1765    }
1766
1767    #[rhai_fn(global)]
1768    #[must_use]
1769    pub const fn set_type_base64(builder: GSDMParamResult) -> GSDMParamResult {
1770        builder.set_type_base64()
1771    }
1772
1773    #[rhai_fn(global)]
1774    #[must_use]
1775    pub const fn set_type_hexbinary(builder: GSDMParamResult) -> GSDMParamResult {
1776        builder.set_type_hexbinary()
1777    }
1778
1779    #[rhai_fn(global)]
1780    #[must_use]
1781    pub const fn set_type_datetime(builder: GSDMParamResult) -> GSDMParamResult {
1782        builder.set_type_datetime()
1783    }
1784
1785    #[rhai_fn(global)]
1786    #[must_use]
1787    pub const fn set_type_decimal(builder: GSDMParamResult) -> GSDMParamResult {
1788        builder.set_type_decimal()
1789    }
1790
1791    #[rhai_fn(global)]
1792    #[must_use]
1793    pub const fn set_type_boolean(builder: GSDMParamResult) -> GSDMParamResult {
1794        builder.set_type_boolean()
1795    }
1796
1797    #[rhai_fn(global)]
1798    #[must_use]
1799    pub const fn set_value_change_allowed(builder: GSDMParamResult) -> GSDMParamResult {
1800        builder.set_value_change_allowed()
1801    }
1802
1803    #[rhai_fn(global)]
1804    #[must_use]
1805    pub const fn set_value_change_will_ignore(builder: GSDMParamResult) -> GSDMParamResult {
1806        builder.set_value_change_will_ignore()
1807    }
1808}
1809
1810/// Supply Rusp GetInstances Message functionality
1811/// ```
1812/// // Rhai script
1813/// # let script = r#"
1814/// let body = rusp::getinstances_builder()
1815///   .with_first_level_only(true)
1816///   .with_obj_paths(["Device."])
1817///   .build();
1818/// rusp::msg_builder()
1819///   .with_msg_id("Foo")
1820///   .with_body(body)
1821///   .build()
1822/// # "#;
1823/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1824/// # assert!(!msg.is_error());
1825/// # assert!(msg.is_request());
1826/// # assert!(!msg.is_response());
1827/// ```
1828#[export_module]
1829pub mod rhai_rusp_getinstances {
1830    use usp_builder::GetInstancesBuilder;
1831
1832    /// Sets up a new USP `GetInstancesBuilder`
1833    #[must_use]
1834    pub const fn getinstances_builder() -> GetInstancesBuilder {
1835        GetInstancesBuilder::new()
1836    }
1837
1838    #[rhai_fn(global)]
1839    #[must_use]
1840    pub const fn with_first_level_only(
1841        builder: GetInstancesBuilder,
1842        first_level_only: bool,
1843    ) -> GetInstancesBuilder {
1844        builder.with_first_level_only(first_level_only)
1845    }
1846
1847    #[rhai_fn(global)]
1848    #[must_use]
1849    pub fn with_obj_paths(builder: GetInstancesBuilder, obj_paths: Array) -> GetInstancesBuilder {
1850        builder.with_obj_paths(obj_paths.into_iter().map(Dynamic::cast).collect())
1851    }
1852
1853    /// Turns the builder into a [`Body`] structure
1854    ///
1855    /// # Errors
1856    ///
1857    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1858    /// incorrect data.
1859    #[rhai_fn(global, return_raw)]
1860    pub fn build(builder: GetInstancesBuilder) -> Result<Body, Box<EvalAltResult>> {
1861        Ok(builder.build().map_err(|e| e.to_string())?)
1862    }
1863}
1864
1865/// Supply Rusp GetInstancesResp Message functionality
1866/// ```
1867/// // Rhai script
1868/// # let script = r#"
1869/// let curr_inst = rusp::curr_instance_builder("Device.")
1870///   .with_unique_keys(#{"Foo": "Bar"});
1871/// let reqpathres = rusp::getinstances_req_path_result_builder("Device.")
1872///   .set_err(7002, "Look, a fancy error")
1873///   .with_curr_insts([curr_inst]);
1874/// let body = rusp::getinstancesresp_builder()
1875///   .with_req_path_results([reqpathres])
1876///   .build();
1877/// rusp::msg_builder()
1878///   .with_msg_id("Foo")
1879///   .with_body(body)
1880///   .build()
1881/// # "#;
1882/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1883/// # assert!(!msg.is_error());
1884/// # assert!(!msg.is_request());
1885/// # assert!(msg.is_response());
1886/// ```
1887#[export_module]
1888pub mod rhai_rusp_getinstancesresp {
1889    use usp_builder::{
1890        CurrInstanceBuilder, GetInstancesRespBuilder, GetInstancesRespReqPathResultBuilder,
1891    };
1892
1893    /// Sets up a new USP `GetInstancesRespBuilder`
1894    #[must_use]
1895    pub const fn getinstancesresp_builder() -> GetInstancesRespBuilder {
1896        GetInstancesRespBuilder::new()
1897    }
1898
1899    #[rhai_fn(global)]
1900    #[must_use]
1901    pub fn with_req_path_results(
1902        builder: GetInstancesRespBuilder,
1903        req_path_results: Array,
1904    ) -> GetInstancesRespBuilder {
1905        builder.with_req_path_results(req_path_results.into_iter().map(Dynamic::cast).collect())
1906    }
1907
1908    #[must_use]
1909    pub fn getinstances_req_path_result_builder(
1910        requested_path: &str,
1911    ) -> GetInstancesRespReqPathResultBuilder {
1912        GetInstancesRespReqPathResultBuilder::new(requested_path.into())
1913    }
1914
1915    #[rhai_fn(global)]
1916    #[must_use]
1917    pub fn set_err(
1918        builder: GetInstancesRespReqPathResultBuilder,
1919        err_code: i64,
1920        err_msg: &str,
1921    ) -> GetInstancesRespReqPathResultBuilder {
1922        builder.set_err(
1923            u32::try_from(err_code).unwrap_or(7003),
1924            (!err_msg.is_empty()).then_some(err_msg.into()),
1925        )
1926    }
1927
1928    #[rhai_fn(global)]
1929    #[must_use]
1930    pub fn with_curr_insts(
1931        builder: GetInstancesRespReqPathResultBuilder,
1932        curr_insts: Array,
1933    ) -> GetInstancesRespReqPathResultBuilder {
1934        builder.with_curr_insts(curr_insts.into_iter().map(Dynamic::cast).collect())
1935    }
1936
1937    #[must_use]
1938    pub fn curr_instance_builder(resolved_path: &str) -> CurrInstanceBuilder {
1939        CurrInstanceBuilder::new(resolved_path.into())
1940    }
1941
1942    #[rhai_fn(global)]
1943    #[must_use]
1944    pub fn with_unique_keys(builder: CurrInstanceBuilder, unique_keys: Map) -> CurrInstanceBuilder {
1945        let unique_keys = unique_keys
1946            .iter()
1947            .map(|(k, v)| (k.to_string(), v.to_string()))
1948            .collect();
1949        builder.with_unique_keys(unique_keys)
1950    }
1951
1952    /// Turns the builder into a [`Body`] structure
1953    ///
1954    /// # Errors
1955    ///
1956    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1957    /// incorrect data.
1958    #[rhai_fn(global, return_raw)]
1959    pub fn build(builder: GetInstancesRespBuilder) -> Result<Body, Box<EvalAltResult>> {
1960        Ok(builder.build().map_err(|e| e.to_string())?)
1961    }
1962}
1963
1964/// Supply Rusp GetSupportedProtocol Message functionality
1965/// ```
1966/// // Rhai script
1967/// # let script = r#"
1968/// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
1969///   .build();
1970/// rusp::msg_builder()
1971///   .with_msg_id("Foo")
1972///   .with_body(body)
1973///   .build()
1974/// # "#;
1975/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
1976/// # assert!(!msg.is_error());
1977/// # assert!(msg.is_request());
1978/// # assert!(!msg.is_response());
1979/// ```
1980#[export_module]
1981pub mod rhai_rusp_getsupportedprotocol {
1982    use usp_builder::GetSupportedProtocolBuilder;
1983
1984    /// Sets up a new USP `GetSupportedProtocolBuilder`
1985    #[must_use]
1986    pub fn getsupportedprotocol_builder(
1987        controller_supported_protocol_versions: &str,
1988    ) -> GetSupportedProtocolBuilder {
1989        GetSupportedProtocolBuilder::new(controller_supported_protocol_versions.into())
1990    }
1991
1992    /// Turns the builder into a [`Body`] structure
1993    ///
1994    /// # Errors
1995    ///
1996    /// This function will return `Err` if the provided `builder` was set up with incomplete or
1997    /// incorrect data.
1998    #[rhai_fn(global, return_raw)]
1999    pub fn build(builder: GetSupportedProtocolBuilder) -> Result<Body, Box<EvalAltResult>> {
2000        Ok(builder.build().map_err(|e| e.to_string())?)
2001    }
2002}
2003
2004/// Supply Rusp GetSupportedProtocolResp Message functionality
2005/// ```
2006/// // Rhai script
2007/// # let script = r#"
2008/// let body = rusp::getsupportedprotocolresp_builder("1.2,1.3")
2009///   .build();
2010/// rusp::msg_builder()
2011///   .with_msg_id("Foo")
2012///   .with_body(body)
2013///   .build()
2014/// # "#;
2015/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2016/// # assert!(!msg.is_error());
2017/// # assert!(!msg.is_request());
2018/// # assert!(msg.is_response());
2019/// ```
2020#[export_module]
2021pub mod rhai_rusp_getsupportedprotocolresp {
2022    use usp_builder::GetSupportedProtocolRespBuilder;
2023
2024    /// Sets up a new USP `GetSupportedProtocolRespBuilder`
2025    #[must_use]
2026    pub fn getsupportedprotocolresp_builder(
2027        agent_supported_protocol_versions: &str,
2028    ) -> GetSupportedProtocolRespBuilder {
2029        GetSupportedProtocolRespBuilder::new(agent_supported_protocol_versions.into())
2030    }
2031
2032    /// Turns the builder into a [`Body`] structure
2033    ///
2034    /// # Errors
2035    ///
2036    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2037    /// incorrect data.
2038    #[rhai_fn(global, return_raw)]
2039    pub fn build(builder: GetSupportedProtocolRespBuilder) -> Result<Body, Box<EvalAltResult>> {
2040        Ok(builder.build().map_err(|e| e.to_string())?)
2041    }
2042}
2043
2044/// Supply Rusp Add Message functionality
2045/// ```
2046/// // Rhai script
2047/// # let script = r#"
2048/// let create_obj = rusp::add_create_object_builder("Device.IP.Interface.")
2049///   .with_param_settings([["Foo", "Bar", true],["Whee", "What?", false]]);
2050/// let body = rusp::add_builder()
2051///   .with_allow_partial(true)
2052///   .with_create_objs([create_obj])
2053///   .build();
2054/// rusp::msg_builder()
2055///   .with_msg_id("Foo")
2056///   .with_body(body)
2057///   .build()
2058/// # "#;
2059/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2060/// # assert!(!msg.is_error());
2061/// # assert!(msg.is_request());
2062/// # assert!(!msg.is_response());
2063/// ```
2064#[export_module]
2065pub mod rhai_rusp_add {
2066    use usp_builder::{AddBuilder, CreateObjectBuilder};
2067
2068    /// Sets up a new USP `AddBuilder`
2069    #[must_use]
2070    pub const fn add_builder() -> AddBuilder {
2071        AddBuilder::new()
2072    }
2073
2074    #[rhai_fn(global)]
2075    #[must_use]
2076    pub const fn with_allow_partial(builder: AddBuilder, allow_partial: bool) -> AddBuilder {
2077        builder.with_allow_partial(allow_partial)
2078    }
2079
2080    #[rhai_fn(global)]
2081    #[must_use]
2082    pub fn with_create_objs(builder: AddBuilder, create_objs: Array) -> AddBuilder {
2083        builder.with_create_objs(create_objs.into_iter().map(Dynamic::cast).collect())
2084    }
2085
2086    #[rhai_fn(global)]
2087    #[must_use]
2088    pub fn add_create_object_builder(obj_path: &str) -> CreateObjectBuilder {
2089        CreateObjectBuilder::new(obj_path.into())
2090    }
2091
2092    ///
2093    /// # Errors
2094    ///
2095    /// This function will return `Err` if the provided `param_settings` cannot be converted into
2096    /// an array of type `(String, String, bool)`.
2097    #[rhai_fn(global, return_raw)]
2098    pub fn with_param_settings(
2099        mut builder: CreateObjectBuilder,
2100        param_settings: Array,
2101    ) -> Result<CreateObjectBuilder, Box<EvalAltResult>> {
2102        let param_settings = param_settings
2103            .into_iter()
2104            .map(|p| {
2105                let el = p.try_cast::<Array>()
2106                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, value: &str, required: bool]".to_string())?;
2107                let el0 = el.first()
2108                    .and_then(|el| el.clone().try_cast::<String>())
2109                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
2110                let el1 = el.get(1)
2111                    .and_then(|el| el.clone().try_cast::<String>())
2112                    .ok_or_else(|| "value (#2) needs to be a string".to_string())?;
2113                let el2 = el.get(2)
2114                    .and_then(|el| el.clone().try_cast::<bool>())
2115                    .ok_or_else(|| "required (#3) needs to be a bool".to_string())?;
2116
2117                Ok((el0, el1, el2))
2118            })
2119            .collect::<Result<Vec<(String, String, bool)>, Box<EvalAltResult>>>()?;
2120        builder = builder.with_param_settings(param_settings);
2121
2122        Ok(builder)
2123    }
2124
2125    /// Turns the builder into a [`Body`] structure
2126    ///
2127    /// # Errors
2128    ///
2129    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2130    /// incorrect data.
2131    #[rhai_fn(global, return_raw)]
2132    pub fn build(builder: AddBuilder) -> Result<Body, Box<EvalAltResult>> {
2133        Ok(builder.build().map_err(|e| e.to_string())?)
2134    }
2135}
2136
2137/// Supply Rusp AddResp Message functionality
2138/// ```
2139/// // Rhai script
2140/// # let script = r#"
2141/// let created_objs = [
2142///   rusp::addresp_created_obj_failure("Foo", 7004, ""),
2143///   rusp::addresp_created_obj_success("Foo", "Foo.Bar.1", [["Bar", 7004, ""]], #{"Foo": "Bar"})
2144/// ];
2145/// let body = rusp::addresp_builder()
2146///   .with_created_obj_results(created_objs)
2147///   .build();
2148/// rusp::msg_builder()
2149///   .with_msg_id("Foo")
2150///   .with_body(body)
2151///   .build()
2152/// # "#;
2153/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2154/// # assert!(!msg.is_error());
2155/// # assert!(!msg.is_request());
2156/// # assert!(msg.is_response());
2157/// ```
2158#[export_module]
2159pub mod rhai_rusp_addresp {
2160    use usp_builder::{
2161        AddOperationStatus, AddRespBuilder, AddRespParameterError, CreatedObjectResultsBuilder,
2162    };
2163
2164    /// Sets up a new USP `AddRespBuilder`
2165    #[must_use]
2166    pub const fn addresp_builder() -> AddRespBuilder {
2167        AddRespBuilder::new()
2168    }
2169
2170    #[rhai_fn(global)]
2171    #[must_use]
2172    pub fn with_created_obj_results(
2173        builder: AddRespBuilder,
2174        created_obj_results: Array,
2175    ) -> AddRespBuilder {
2176        let created_obj_results = created_obj_results.into_iter().map(Dynamic::cast).collect();
2177        builder.with_created_obj_results(created_obj_results)
2178    }
2179
2180    #[rhai_fn(global)]
2181    #[must_use]
2182    pub fn addresp_created_obj_failure(
2183        requested_path: &str,
2184        err_code: i64,
2185        err_msg: &str,
2186    ) -> CreatedObjectResultsBuilder {
2187        let oper_status = AddOperationStatus::new().set_failure(
2188            u32::try_from(err_code).unwrap_or(7003),
2189            (!err_msg.is_empty()).then_some(err_msg.into()),
2190        );
2191        CreatedObjectResultsBuilder::new(requested_path.into(), oper_status)
2192    }
2193
2194    ///
2195    /// # Errors
2196    ///
2197    /// This function will return `Err` if the provided `param_errs` cannot be converted into
2198    /// an array of type `(String, u32, String)`.
2199    #[rhai_fn(global, return_raw)]
2200    pub fn addresp_created_obj_success(
2201        requested_path: &str,
2202        instantiated_path: &str,
2203        param_errs: Array,
2204        unique_keys: Map,
2205    ) -> Result<CreatedObjectResultsBuilder, Box<EvalAltResult>> {
2206        let param_errs = param_errs
2207            .into_iter()
2208            .map(|p| {
2209                let el = p.try_cast::<Array>()
2210                    .ok_or_else(|| "Expected to have an array of arrays [param: &str, err_code: u32, err_msg: &str]".to_string())?;
2211                let el0 = el.first()
2212                    .and_then(|el| el.clone().try_cast::<String>())
2213                    .ok_or_else(|| "param (#1) needs to be a string".to_string())?;
2214                let el1 = el.get(1)
2215                    .and_then(|el| el.clone().try_cast::<i64>())
2216                    .ok_or_else(|| "err_code (#2) needs to be a u32".to_string())?;
2217                let el2 = el.get(2)
2218                    .and_then(|el| el.clone().try_cast::<String>())
2219                    .ok_or_else(|| "err_msg (#3) needs to be a string".to_string())?;
2220
2221                Ok(AddRespParameterError{param: el0, err_code: u32::try_from(el1).unwrap_or(7003) , err_msg: el2 })
2222            })
2223            .collect::<Result<Vec<AddRespParameterError>, Box<EvalAltResult>>>()?;
2224
2225        let unique_keys = unique_keys
2226            .iter()
2227            .map(|(k, v)| (k.to_string(), v.to_string()))
2228            .collect();
2229
2230        Ok(CreatedObjectResultsBuilder::new(
2231            requested_path.into(),
2232            AddOperationStatus::new().set_success(
2233                instantiated_path.into(),
2234                param_errs,
2235                unique_keys,
2236            ),
2237        ))
2238    }
2239
2240    /// Turns the builder into a [`Body`] structure
2241    ///
2242    /// # Errors
2243    ///
2244    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2245    /// incorrect data.
2246    #[rhai_fn(global, return_raw)]
2247    pub fn build(builder: AddRespBuilder) -> Result<Body, Box<EvalAltResult>> {
2248        Ok(builder.build().map_err(|e| e.to_string())?)
2249    }
2250}
2251
2252/// Supply Rusp Notify Message functionality
2253///
2254/// This module facilities the assembly of [USP Notify
2255/// Message](https://usp.technology/specification/index.htm#sec:notify) [`bodies`](Body).
2256#[export_module]
2257pub mod rhai_rusp_notify {
2258    use usp_builder::NotifyBuilder;
2259
2260    /// Sets up a new USP `NotifyBuilder`
2261    #[must_use]
2262    pub fn notify_builder(subscription_id: &str) -> NotifyBuilder {
2263        usp_builder::NotifyBuilder::new(subscription_id.into())
2264    }
2265
2266    /// Set a notification body of type `ValueChange`
2267    ///
2268    /// ```
2269    /// // Rhai script
2270    /// # let script = r#"
2271    /// let body = rusp::notify_builder("not-sub")
2272    ///   .with_event("Device.", "Boot!", #{"CommandKey": "ck"})
2273    ///   .build();
2274    /// rusp::msg_builder()
2275    ///   .with_msg_id("Foo")
2276    ///   .with_body(body)
2277    ///   .build()
2278    /// # "#;
2279    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2280    /// # assert!(!msg.is_error());
2281    /// # assert!(msg.is_request());
2282    /// # assert!(!msg.is_response());
2283    /// ```
2284    #[rhai_fn(global)]
2285    #[must_use]
2286    pub fn with_event(
2287        builder: NotifyBuilder,
2288        obj_path: &str,
2289        event_name: &str,
2290        params: Map,
2291    ) -> NotifyBuilder {
2292        let params = params
2293            .iter()
2294            .map(|(k, v)| (k.to_string(), v.to_string()))
2295            .collect();
2296        builder.with_event(obj_path.into(), event_name.into(), params)
2297    }
2298
2299    /// Set a notification body of type `ValueChange`
2300    ///
2301    /// ```
2302    /// // Rhai script
2303    /// # let script = r#"
2304    /// let body = rusp::notify_builder("not-sub")
2305    ///   .with_value_change("Device.Foo", "bar")
2306    ///   .build();
2307    /// rusp::msg_builder()
2308    ///   .with_msg_id("Foo")
2309    ///   .with_body(body)
2310    ///   .build()
2311    /// # "#;
2312    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2313    /// # assert!(!msg.is_error());
2314    /// # assert!(msg.is_request());
2315    /// # assert!(!msg.is_response());
2316    /// ```
2317    #[rhai_fn(global)]
2318    #[must_use]
2319    pub fn with_value_change(
2320        builder: NotifyBuilder,
2321        param_path: &str,
2322        param_value: &str,
2323    ) -> NotifyBuilder {
2324        builder.with_value_change(param_path.into(), param_value.into())
2325    }
2326
2327    /// Set a notification body of type `ObjectCreation`
2328    ///
2329    /// ```
2330    /// // Rhai script
2331    /// # let script = r#"
2332    /// let body = rusp::notify_builder("not-sub")
2333    ///   .with_send_resp(true)
2334    ///   .with_object_creation("Device.Foo.1.", #{"Alias": "cpe-01"})
2335    ///   .build();
2336    /// rusp::msg_builder()
2337    ///   .with_msg_id("Foo")
2338    ///   .with_body(body)
2339    ///   .build()
2340    /// # "#;
2341    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2342    /// # assert!(!msg.is_error());
2343    /// # assert!(msg.is_request());
2344    /// # assert!(!msg.is_response());
2345    /// ```
2346    #[rhai_fn(global)]
2347    #[must_use]
2348    pub fn with_object_creation(
2349        builder: NotifyBuilder,
2350        obj_path: &str,
2351        unique_keys: Map,
2352    ) -> NotifyBuilder {
2353        let unique_keys = unique_keys
2354            .iter()
2355            .map(|(k, v)| (k.to_string(), v.to_string()))
2356            .collect();
2357        builder.with_object_creation(obj_path.into(), unique_keys)
2358    }
2359
2360    /// Set a notification body of type `ObjectDeletion`
2361    ///
2362    /// ```
2363    /// // Rhai script
2364    /// # let script = r#"
2365    /// let body = rusp::notify_builder("not-sub")
2366    ///   .with_send_resp(true)
2367    ///   .with_object_deletion("Device.Foo.1.")
2368    ///   .build();
2369    /// rusp::msg_builder()
2370    ///   .with_msg_id("Foo")
2371    ///   .with_body(body)
2372    ///   .build()
2373    /// # "#;
2374    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2375    /// # assert!(!msg.is_error());
2376    /// # assert!(msg.is_request());
2377    /// # assert!(!msg.is_response());
2378    /// ```
2379    #[rhai_fn(global)]
2380    #[must_use]
2381    pub fn with_object_deletion(builder: NotifyBuilder, obj_path: &str) -> NotifyBuilder {
2382        builder.with_object_deletion(obj_path.into())
2383    }
2384
2385    /// Set a notification body of type `OperationComplete` with success
2386    ///
2387    /// ```
2388    /// // Rhai script
2389    /// # let script = r#"
2390    /// let body = rusp::notify_builder("not-sub")
2391    ///   .with_send_resp(true)
2392    ///   .with_operation_complete_output_args("Device.", "Reboot()", "Foo", #{"Status": "Complete", "Results": ""})
2393    ///   .build();
2394    /// rusp::msg_builder()
2395    ///   .with_msg_id("Foo")
2396    ///   .with_body(body)
2397    ///   .build()
2398    /// # "#;
2399    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2400    /// # assert!(!msg.is_error());
2401    /// # assert!(msg.is_request());
2402    /// # assert!(!msg.is_response());
2403    /// ```
2404    #[rhai_fn(global)]
2405    #[must_use]
2406    pub fn with_operation_complete_output_args(
2407        builder: NotifyBuilder,
2408        obj_path: &str,
2409        command_name: &str,
2410        command_key: &str,
2411        output_args: Map,
2412    ) -> NotifyBuilder {
2413        let output_args = output_args
2414            .iter()
2415            .map(|(k, v)| (k.to_string(), v.to_string()))
2416            .collect();
2417        builder.with_operation_complete_output_args(
2418            obj_path.into(),
2419            command_name.into(),
2420            command_key.into(),
2421            output_args,
2422        )
2423    }
2424
2425    /// Set a notification body of type `OperationComplete` with failure
2426    ///
2427    /// ```
2428    /// // Rhai script
2429    /// # let script = r#"
2430    /// let body = rusp::notify_builder("not-sub")
2431    ///   .with_send_resp(true)
2432    ///   .with_operation_complete_cmd_failure("Device.", "Reboot()", "Foo", 7002, "Don't want to")
2433    ///   .build();
2434    /// rusp::msg_builder()
2435    ///   .with_msg_id("Foo")
2436    ///   .with_body(body)
2437    ///   .build()
2438    /// # "#;
2439    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2440    /// # assert!(!msg.is_error());
2441    /// # assert!(msg.is_request());
2442    /// # assert!(!msg.is_response());
2443    /// ```
2444    #[rhai_fn(global)]
2445    #[must_use]
2446    pub fn with_operation_complete_cmd_failure(
2447        builder: NotifyBuilder,
2448        obj_path: &str,
2449        command_name: &str,
2450        command_key: &str,
2451        err_code: i64,
2452        err_msg: &str,
2453    ) -> NotifyBuilder {
2454        builder.with_operation_complete_cmd_failure(
2455            obj_path.into(),
2456            command_name.into(),
2457            command_key.into(),
2458            u32::try_from(err_code).unwrap_or(7003),
2459            err_msg.into(),
2460        )
2461    }
2462
2463    /// Set a notification body of type `OnBoardRequest`
2464    ///
2465    /// ```
2466    /// // Rhai script
2467    /// # let script = r#"
2468    /// let body = rusp::notify_builder("not-sub")
2469    ///   .with_send_resp(true)
2470    ///   .with_onboard_request("00CAFE", "None", "000111", "1.3")
2471    ///   .build();
2472    /// rusp::msg_builder()
2473    ///   .with_msg_id("Foo")
2474    ///   .with_body(body)
2475    ///   .build()
2476    /// # "#;
2477    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2478    /// # assert!(!msg.is_error());
2479    /// # assert!(msg.is_request());
2480    /// # assert!(!msg.is_response());
2481    /// ```
2482    #[rhai_fn(global)]
2483    #[must_use]
2484    pub fn with_onboard_request(
2485        builder: NotifyBuilder,
2486        oui: &str,
2487        product_class: &str,
2488        serial_number: &str,
2489        aspv: &str,
2490    ) -> NotifyBuilder {
2491        builder.with_onboard_request(
2492            oui.into(),
2493            product_class.into(),
2494            serial_number.into(),
2495            aspv.into(),
2496        )
2497    }
2498
2499    /// Sets the `send_resp` flag in the notification
2500    ///
2501    /// Setting this to `true` causes the recipient to acknowledge the received notification.
2502    /// Conversely, setting this to `false` also disables the retry mechanism so it should usually
2503    /// be set to `true`.
2504    ///
2505    /// ```
2506    /// // Rhai script
2507    /// # let script = r#"
2508    /// let body = rusp::notify_builder("not-sub")
2509    ///   .with_send_resp(true)
2510    ///   .with_operation_complete_cmd_failure("Device.", "Reboot()", "Foo", 7002, "Don't want to")
2511    ///   .build();
2512    /// rusp::msg_builder()
2513    ///   .with_msg_id("Foo")
2514    ///   .with_body(body)
2515    ///   .build()
2516    /// # "#;
2517    /// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2518    /// # assert!(!msg.is_error());
2519    /// # assert!(msg.is_request());
2520    /// # assert!(!msg.is_response());
2521    /// ```
2522    #[rhai_fn(global)]
2523    #[must_use]
2524    pub const fn with_send_resp(builder: NotifyBuilder, send_resp: bool) -> NotifyBuilder {
2525        builder.with_send_resp(send_resp)
2526    }
2527
2528    /// Turns the builder into a [`Body`] structure
2529    ///
2530    /// # Errors
2531    ///
2532    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2533    /// incorrect data.
2534    #[rhai_fn(global, return_raw)]
2535    pub fn build(builder: NotifyBuilder) -> Result<Body, Box<EvalAltResult>> {
2536        Ok(builder.build().map_err(|e| e.to_string())?)
2537    }
2538}
2539
2540/// Supply Rusp NotifyResp Message functionality
2541/// ```
2542/// let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(r#"
2543///     let body = rusp::notifyresp_builder("sub")
2544///         .build();
2545///     rusp::msg_builder()
2546///         .with_msg_id("Foo")
2547///         .with_body(body)
2548///         .build()
2549/// "#).unwrap();
2550/// assert!(!msg.is_error());
2551/// assert!(!msg.is_request());
2552/// assert!(msg.is_response());
2553/// ```
2554#[export_module]
2555pub mod rhai_rusp_notifyresp {
2556    use usp_builder::NotifyRespBuilder;
2557
2558    /// Sets up a new USP `NotifyRespBuilder`
2559    #[must_use]
2560    pub fn notifyresp_builder(subscription_id: &str) -> NotifyRespBuilder {
2561        usp_builder::NotifyRespBuilder::new(subscription_id.into())
2562    }
2563
2564    /// Turns the builder into a [`Body`] structure
2565    ///
2566    /// # Errors
2567    ///
2568    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2569    /// incorrect data.
2570    #[rhai_fn(global, return_raw)]
2571    pub fn build(builder: NotifyRespBuilder) -> Result<Body, Box<EvalAltResult>> {
2572        Ok(builder.build().map_err(|e| e.to_string())?)
2573    }
2574}
2575
2576/// Supply Rusp Operate Message functionality
2577/// ```
2578/// # let script = r#"
2579/// // Rhai script
2580/// let body = rusp::operate_builder("Device.Reboot()")
2581///   .with_command_key("Command")
2582///   .with_send_resp(true)
2583///   .with_input_args(#{"Foo": "Bar", "Baz": "Bam"})
2584///   .build();
2585/// rusp::msg_builder()
2586///   .with_msg_id("Foo")
2587///   .with_body(body)
2588///   .build()
2589/// # "#;
2590/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2591/// # assert!(!msg.is_error());
2592/// # assert!(msg.is_request());
2593/// # assert!(!msg.is_response());
2594/// ```
2595#[export_module]
2596pub mod rhai_rusp_operate {
2597    use usp_builder::OperateBuilder;
2598
2599    /// Sets up a new USP `OperateBuilder`
2600    #[must_use]
2601    pub fn operate_builder(command: &str) -> OperateBuilder {
2602        OperateBuilder::new(command.into())
2603    }
2604
2605    #[rhai_fn(global)]
2606    #[must_use]
2607    pub fn with_command_key(builder: OperateBuilder, command_key: &str) -> OperateBuilder {
2608        builder.with_command_key(command_key.into())
2609    }
2610
2611    #[rhai_fn(global)]
2612    #[must_use]
2613    pub const fn with_send_resp(builder: OperateBuilder, send_resp: bool) -> OperateBuilder {
2614        builder.with_send_resp(send_resp)
2615    }
2616
2617    #[rhai_fn(global)]
2618    #[must_use]
2619    pub fn with_input_args(builder: OperateBuilder, input_args: Map) -> OperateBuilder {
2620        let input_args = input_args
2621            .iter()
2622            .map(|(k, v)| (k.to_string(), v.to_string()))
2623            .collect();
2624        builder.with_input_args(input_args)
2625    }
2626
2627    /// Turns the builder into a [`Body`] structure
2628    ///
2629    /// # Errors
2630    ///
2631    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2632    /// incorrect data.
2633    #[rhai_fn(global, return_raw)]
2634    pub fn build(builder: OperateBuilder) -> Result<Body, Box<EvalAltResult>> {
2635        Ok(builder.build().map_err(|e| e.to_string())?)
2636    }
2637}
2638
2639/// Supply Rusp OperateResp Message functionality
2640/// ```
2641/// // Rhai script
2642/// # let script = r#"
2643/// let oper_results = [
2644///   rusp::operateresp_result_failure("Device.SelfTestDiagnostics()", 7004, ""),
2645///   rusp::operateresp_result_path("Device.Foo()", "Device.LocalAgent.Request.25."),
2646///   rusp::operateresp_result_output_args("Device.Bar()", #{"Baz": "Foo"}),
2647/// ];
2648/// let body = rusp::operateresp_builder()
2649///   .with_operation_results(oper_results)
2650///   .build();
2651/// rusp::msg_builder()
2652///   .with_msg_id("Foo")
2653///   .with_body(body)
2654///   .build()
2655/// # "#;
2656/// # let msg = rhai_rusp::eval_rusp::<rusp_lib::usp::Msg>(script).unwrap();
2657/// # assert!(!msg.is_error());
2658/// # assert!(!msg.is_request());
2659/// # assert!(msg.is_response());
2660/// ```
2661#[export_module]
2662pub mod rhai_rusp_operateresp {
2663    use usp_builder::{OperateRespBuilder, OperateRespResultBuilder};
2664
2665    /// Sets up a new USP `OperateRespBuilder`
2666    #[must_use]
2667    pub const fn operateresp_builder() -> OperateRespBuilder {
2668        OperateRespBuilder::new()
2669    }
2670
2671    #[rhai_fn(global)]
2672    #[must_use]
2673    pub fn with_operation_results(
2674        builder: OperateRespBuilder,
2675        operation_results: Array,
2676    ) -> OperateRespBuilder {
2677        let operation_results = operation_results.into_iter().map(Dynamic::cast).collect();
2678        builder.with_operation_results(operation_results)
2679    }
2680
2681    #[rhai_fn(global)]
2682    #[must_use]
2683    pub fn operateresp_result_failure(
2684        executed_command: &str,
2685        err_code: i64,
2686        err_msg: &str,
2687    ) -> OperateRespResultBuilder {
2688        OperateRespResultBuilder::new(executed_command.into()).set_failure(
2689            u32::try_from(err_code).unwrap_or(7003),
2690            (!err_msg.is_empty()).then_some(err_msg.into()),
2691        )
2692    }
2693
2694    #[rhai_fn(global)]
2695    #[must_use]
2696    pub fn operateresp_result_path(
2697        executed_command: &str,
2698        req_obj_path: &str,
2699    ) -> OperateRespResultBuilder {
2700        OperateRespResultBuilder::new(executed_command.into()).set_path(req_obj_path.into())
2701    }
2702
2703    #[rhai_fn(global)]
2704    #[must_use]
2705    pub fn operateresp_result_output_args(
2706        executed_command: &str,
2707        output_args: Map,
2708    ) -> OperateRespResultBuilder {
2709        let output_args = output_args
2710            .iter()
2711            .map(|(k, v)| (k.to_string(), v.to_string()))
2712            .collect();
2713
2714        OperateRespResultBuilder::new(executed_command.into()).set_output_args(output_args)
2715    }
2716
2717    /// Turns the builder into a [`Body`] structure
2718    ///
2719    /// # Errors
2720    ///
2721    /// This function will return `Err` if the provided `builder` was set up with incomplete or
2722    /// incorrect data.
2723    #[rhai_fn(global, return_raw)]
2724    pub fn build(builder: OperateRespBuilder) -> Result<Body, Box<EvalAltResult>> {
2725        Ok(builder.build().map_err(|e| e.to_string())?)
2726    }
2727}
2728
2729/// Supply Rusp de-/serialization functionality
2730/// ```
2731/// // Rhai script
2732/// let script = r#"
2733///     rusp::record_builder()
2734///         .with_version("1.3")
2735///         .with_to_id("proto::to")
2736///         .with_from_id("proto::from")
2737///         .as_websocket_connect_record()
2738///         .build()
2739///         .to_string()
2740/// "#;
2741/// let record = rhai_rusp::eval_rusp::<String>(script).unwrap();
2742///
2743/// assert_eq!(record, "{\n  \"version\": \"1.3\",\n  \"to_id\": \"proto::to\",\n  \"from_id\": \"proto::from\",\n  \"payload_security\": \"PLAINTEXT\",\n  \"mac_signature\": [],\n  \"sender_cert\": [],\n  \"websocket_connect\": null\n}");
2744/// ```
2745#[export_module]
2746pub mod rhai_rusp {
2747    use std::io::{Read, Write as _};
2748
2749    use rusp_lib::usp_decoder::{try_decode_msg, try_decode_record};
2750    use usp_builder::{MsgBuilder, RecordBuilder};
2751    use usp_record::mod_Record::OneOfrecord_type;
2752
2753    /// Creates a new [`MsgBuilder`] with the given message [`Body`]. This is a shortcut to directly
2754    /// chain operations without using nested calls.
2755    /// ```
2756    /// // Rhai script
2757    /// # let script = r#"
2758    /// let msg =
2759    ///     rusp::get_builder().with_max_depth(1).with_params(["Device."]).build().as_msg_builder().with_msg_id("id").build();
2760    ///  msg.to_string()
2761    /// # "#;
2762    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
2763    /// # assert_eq!(msg, "{\n  \"Header\": {\n    \"msg_id\": \"id\",\n    \"msg_type\": \"GET\"\n  },\n  \"Body\": {\n    \"Request\": {\n      \"Get\": {\n        \"param_paths\": [\n          \"Device.\"\n        ],\n        \"max_depth\": 1\n      }\n    }\n  }\n}");
2764    /// ```
2765    ///
2766    /// This example will return a JSON output like:
2767    /// ```text
2768    /// {
2769    ///   "Header": {
2770    ///     "msg_id": "id",
2771    ///     "msg_type": "GET"
2772    ///   },
2773    ///   "Body": {
2774    ///     "Request": {
2775    ///       "Get": {
2776    ///         "param_paths": [
2777    ///           "Device."
2778    ///         ],
2779    ///         "max_depth": 1
2780    ///       }
2781    ///     }
2782    ///   }
2783    /// }
2784    /// ```
2785    ///
2786    /// # Errors
2787    ///
2788    /// This function will return `Err` containing a textual description of the encountered error if
2789    /// the conversion into a `MsgBuilder` fails.
2790    #[rhai_fn(global, return_raw)]
2791    pub fn as_msg_builder(body: Body) -> Result<MsgBuilder, Box<EvalAltResult>> {
2792        Ok(MsgBuilder::new().with_body(body))
2793    }
2794
2795    /// Creates a new [`RecordBuilder`] with the given [`MsgBuilder`] as "no_session_context"
2796    /// payload. This is a shortcut to directly chain operations without using nested calls.
2797    /// This function is polymorphic in Rhai and available as `as_no_session_record_builder()`
2798    /// ```
2799    /// // Rhai script
2800    /// # let script = r#"
2801    /// let msg =
2802    ///     rusp::get_builder().with_params(["Device."]).build().as_msg_builder().with_msg_id("id").as_no_session_record_builder().with_to_id("proto::to").with_from_id("proto::from").build();
2803    ///  msg.to_string()
2804    /// # "#;
2805    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
2806    /// # assert_eq!(msg, "{\n  \"version\": \"1.4\",\n  \"to_id\": \"proto::to\",\n  \"from_id\": \"proto::from\",\n  \"payload_security\": \"PLAINTEXT\",\n  \"mac_signature\": [],\n  \"sender_cert\": [],\n  \"payload\": {\n    \"Header\": {\n      \"msg_id\": \"id\",\n      \"msg_type\": \"GET\"\n    },\n    \"Body\": {\n      \"Request\": {\n        \"Get\": {\n          \"param_paths\": [\n            \"Device.\"\n          ],\n          \"max_depth\": 0\n        }\n      }\n    }\n  }\n}");
2807    /// ```
2808    ///
2809    /// This example will return a JSON output like:
2810    /// ```text
2811    /// {
2812    ///   "version": "1.4",
2813    ///   "to_id": "proto::to",
2814    ///   "from_id": "proto::from",
2815    ///   "payload_security": "PLAINTEXT",
2816    ///   "mac_signature": [],
2817    ///   "sender_cert": [],
2818    ///   "payload": {
2819    ///     "Header": {
2820    ///       "msg_id": "id",
2821    ///       "msg_type": "GET"
2822    ///     },
2823    ///     "Body": {
2824    ///       "Request": {
2825    ///         "Get": {
2826    ///           "param_paths": [
2827    ///             "Device."
2828    ///           ],
2829    ///           "max_depth": 0
2830    ///         }
2831    ///       }
2832    ///     }
2833    ///   }
2834    /// }
2835    /// ```
2836    ///
2837    /// # Errors
2838    ///
2839    /// This function will return `Err` containing a textual description of the encountered error if
2840    /// the conversion into a `RecordBuilder` fails.
2841    #[rhai_fn(global, name = "as_no_session_record_builder", return_raw)]
2842    pub fn msg_builder_as_no_session_record_builder(
2843        builder: MsgBuilder,
2844    ) -> Result<RecordBuilder, Box<EvalAltResult>> {
2845        let msg = builder.build().map_err(|e| e.to_string())?;
2846        Ok(RecordBuilder::new().with_no_session_context_payload(&msg))
2847    }
2848
2849    /// Creates a new [`RecordBuilder`] with the given [`Msg`] as "no_session_context"
2850    /// payload. This is a shortcut to directly chain operations without using nested calls.
2851    /// This function is polymorphic in Rhai and available as `as_no_session_record_builder()`
2852    /// ```
2853    /// // Rhai script
2854    /// # let script = r#"
2855    /// let msg =
2856    ///     rusp::get_builder().with_params(["Device."]).build().as_msg_builder().with_msg_id("id").build().as_no_session_record_builder().with_to_id("proto::to").with_from_id("proto::from").build();
2857    ///  msg.to_string()
2858    /// # "#;
2859    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
2860    /// # assert_eq!(msg, "{\n  \"version\": \"1.4\",\n  \"to_id\": \"proto::to\",\n  \"from_id\": \"proto::from\",\n  \"payload_security\": \"PLAINTEXT\",\n  \"mac_signature\": [],\n  \"sender_cert\": [],\n  \"payload\": {\n    \"Header\": {\n      \"msg_id\": \"id\",\n      \"msg_type\": \"GET\"\n    },\n    \"Body\": {\n      \"Request\": {\n        \"Get\": {\n          \"param_paths\": [\n            \"Device.\"\n          ],\n          \"max_depth\": 0\n        }\n      }\n    }\n  }\n}");
2861    /// ```
2862    ///
2863    /// This example will return a JSON output like:
2864    /// ```text
2865    /// {
2866    ///   "version": "1.4",
2867    ///   "to_id": "proto::to",
2868    ///   "from_id": "proto::from",
2869    ///   "payload_security": "PLAINTEXT",
2870    ///   "mac_signature": [],
2871    ///   "sender_cert": [],
2872    ///   "payload": {
2873    ///     "Header": {
2874    ///       "msg_id": "id",
2875    ///       "msg_type": "GET"
2876    ///     },
2877    ///     "Body": {
2878    ///       "Request": {
2879    ///         "Get": {
2880    ///           "param_paths": [
2881    ///             "Device."
2882    ///           ],
2883    ///           "max_depth": 0
2884    ///         }
2885    ///       }
2886    ///     }
2887    ///   }
2888    /// }
2889    /// ```
2890    ///
2891    /// # Errors
2892    ///
2893    /// This function will return `Err` containing a textual description of the encountered error
2894    /// if the conversion into a `RecordBuilder` fails.
2895    #[rhai_fn(global, name = "as_no_session_record_builder", return_raw)]
2896    pub fn msg_as_no_session_record_builder(msg: Msg) -> Result<RecordBuilder, Box<EvalAltResult>> {
2897        Ok(RecordBuilder::new().with_no_session_context_payload(&msg))
2898    }
2899
2900    /// Render a USP Body into JSON format, this function is polymorphic in Rhai and available as `to_string()`
2901    /// ```
2902    /// // Rhai script
2903    /// # let script = r#"
2904    /// let body = rusp::get_builder().with_max_depth(1).with_params(["Device."]).build();
2905    /// body.to_string()
2906    /// # "#;
2907    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
2908    /// # assert_eq!(msg, "{\n  \"Request\": {\n    \"Get\": {\n      \"param_paths\": [\n        \"Device.\"\n      ],\n      \"max_depth\": 1\n    }\n  }\n}");
2909    /// ```
2910    ///
2911    /// This example will return a JSON output like:
2912    /// ```text
2913    /// {
2914    ///   "Request": {
2915    ///     "Get": {
2916    ///       "param_paths": [
2917    ///         "Device."
2918    ///       ],
2919    ///       "max_depth": 1
2920    ///     }
2921    ///   }
2922    /// }
2923    /// ```
2924    ///
2925    /// `to_string()` is also implicitly called by the `print()` function
2926    ///
2927    /// # Errors
2928    ///
2929    /// This function will return `Err` containing a textual description of the encountered error if
2930    /// the serialization of the structure into JSON format fails.
2931    #[rhai_fn(global, name = "to_string", return_raw)]
2932    pub fn body_to_string(body: &mut Body) -> Result<String, Box<EvalAltResult>> {
2933        body_to_json(body)
2934    }
2935
2936    /// Render a [`Msg`] into JSON format, this function is polymorphic in Rhai and available as `to_string()`
2937    /// ```
2938    /// // Rhai script
2939    /// # let script = r#"
2940    /// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
2941    ///     .build();
2942    /// rusp::msg_builder()
2943    ///     .with_msg_id("Foo")
2944    ///     .with_body(body)
2945    ///     .build()
2946    ///     .to_string()
2947    /// # "#;
2948    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
2949    /// # assert_eq!(msg, "{\n  \"Header\": {\n    \"msg_id\": \"Foo\",\n    \"msg_type\": \"GET_SUPPORTED_PROTO\"\n  },\n  \"Body\": {\n    \"Request\": {\n      \"GetSupportedProtocol\": {\n        \"controller_supported_protocol_versions\": \"1.3,1.4\"\n      }\n    }\n  }\n}");
2950    /// ```
2951    ///
2952    /// This example will return a JSON output like:
2953    /// ```text
2954    /// {
2955    ///   "Header": {
2956    ///     "msg_id": "Foo",
2957    ///     "msg_type": "GET_SUPPORTED_PROTO"
2958    ///   },
2959    ///   "Body": {
2960    ///     "Request": {
2961    ///       "GetSupportedProtocol": {
2962    ///         "controller_supported_protocol_versions": "1.3,1.4"
2963    ///       }
2964    ///     }
2965    ///   }
2966    /// }
2967    /// ```
2968    ///
2969    /// `to_string()` is also implicitly called by the `print()` function
2970    ///
2971    /// # Errors
2972    ///
2973    /// This function will return `Err` containing a textual description of the encountered error if
2974    /// the serialization of the structure into JSON format fails.
2975    #[rhai_fn(global, name = "to_string", return_raw)]
2976    pub fn msg_to_string(msg: &mut Msg) -> Result<String, Box<EvalAltResult>> {
2977        msg_to_json(msg)
2978    }
2979
2980    /// Render a [`Record`] into JSON format, this function is polymorphic in Rhai and available as `to_string()`
2981    /// ```
2982    /// // Rhai script
2983    /// # let script = r#"
2984    /// rusp::record_builder()
2985    ///   .with_version("1.3")
2986    ///   .with_to_id("proto::to")
2987    ///   .with_from_id("proto::from")
2988    ///   .as_websocket_connect_record()
2989    ///   .build()
2990    ///   .to_string()
2991    /// # "#;
2992    /// # let record = rhai_rusp::eval_rusp::<String>(script).unwrap();
2993    /// # assert_eq!(record, "{\n  \"version\": \"1.3\",\n  \"to_id\": \"proto::to\",\n  \"from_id\": \"proto::from\",\n  \"payload_security\": \"PLAINTEXT\",\n  \"mac_signature\": [],\n  \"sender_cert\": [],\n  \"websocket_connect\": null\n}");
2994    /// ```
2995    ///
2996    /// This example will return a JSON output like:
2997    /// ```text
2998    /// {
2999    ///   "version": "1.3",
3000    ///   "to_id": "proto::to",
3001    ///   "from_id": "proto::from",
3002    ///   "payload_security": "PLAINTEXT",
3003    ///   "mac_signature": [],
3004    ///   "sender_cert": [],
3005    ///   "websocket_connect": null
3006    /// }
3007    /// ```
3008    ///
3009    /// `to_string()` is also implicitly called by the `print()` function
3010    ///
3011    /// # Errors
3012    ///
3013    /// This function will return `Err` containing a textual description of the encountered error if
3014    /// the serialization of the structure into JSON format fails.
3015    #[rhai_fn(global, name = "to_string", return_raw)]
3016    pub fn record_to_string(record: &mut Record) -> Result<String, Box<EvalAltResult>> {
3017        record_to_json(record)
3018    }
3019
3020    /// Render a USP Body into JSON format, this function is polymorphic in Rhai and available as `to_json()`
3021    /// ```
3022    /// // Rhai script
3023    /// # let script = r#"
3024    /// let body = rusp::get_builder().with_max_depth(1).with_params(["Device."]).build();
3025    /// body.to_json()
3026    /// # "#;
3027    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
3028    /// # assert_eq!(msg, "{\n  \"Request\": {\n    \"Get\": {\n      \"param_paths\": [\n        \"Device.\"\n      ],\n      \"max_depth\": 1\n    }\n  }\n}");
3029    /// ```
3030    ///
3031    /// This example will return a JSON output like:
3032    /// ```text
3033    /// {
3034    ///   "Request": {
3035    ///     "Get": {
3036    ///       "param_paths": [
3037    ///         "Device."
3038    ///       ],
3039    ///       "max_depth": 1
3040    ///     }
3041    ///   }
3042    /// }
3043    /// ```
3044    ///
3045    /// # Errors
3046    ///
3047    /// This function will return `Err` containing a textual description of the encountered error if
3048    /// the serialization of the structure into JSON format fails.
3049    #[rhai_fn(global, name = "to_json", return_raw)]
3050    pub fn body_to_json(body: &mut Body) -> Result<String, Box<EvalAltResult>> {
3051        Ok(serde_json::to_string_pretty(&body).map_err(|e| e.to_string())?)
3052    }
3053
3054    /// Render a [`Msg`] into JSON format, this function is polymorphic in Rhai and available as `to_json()`
3055    /// ```
3056    /// // Rhai script
3057    /// # let script = r#"
3058    /// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
3059    ///     .build();
3060    /// rusp::msg_builder()
3061    ///     .with_msg_id("Foo")
3062    ///     .with_body(body)
3063    ///     .build()
3064    ///     .to_json()
3065    /// # "#;
3066    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
3067    /// # assert_eq!(msg, "{\n  \"Header\": {\n    \"msg_id\": \"Foo\",\n    \"msg_type\": \"GET_SUPPORTED_PROTO\"\n  },\n  \"Body\": {\n    \"Request\": {\n      \"GetSupportedProtocol\": {\n        \"controller_supported_protocol_versions\": \"1.3,1.4\"\n      }\n    }\n  }\n}");
3068    /// ```
3069    ///
3070    /// This example will return a JSON output like:
3071    /// ```text
3072    /// {
3073    ///   "Header": {
3074    ///     "msg_id": "Foo",
3075    ///     "msg_type": "GET_SUPPORTED_PROTO"
3076    ///   },
3077    ///   "Body": {
3078    ///     "Request": {
3079    ///       "GetSupportedProtocol": {
3080    ///         "controller_supported_protocol_versions": "1.3,1.4"
3081    ///       }
3082    ///     }
3083    ///   }
3084    /// }
3085    /// ```
3086    ///
3087    /// # Errors
3088    ///
3089    /// This function will return `Err` containing a textual description of the encountered error if
3090    /// the serialization of the structure into JSON format fails.
3091    #[rhai_fn(global, name = "to_json", return_raw)]
3092    pub fn msg_to_json(msg: &mut Msg) -> Result<String, Box<EvalAltResult>> {
3093        Ok(serde_json::to_string_pretty(&msg).map_err(|e| e.to_string())?)
3094    }
3095
3096    /// Render a [`Msg`] into JSON format, this function is polymorphic in Rhai and available as `to_json()`
3097    /// ```
3098    /// // Rhai script
3099    /// # let script = r#"
3100    /// rusp::record_builder()
3101    ///   .with_version("1.3")
3102    ///   .with_to_id("proto::to")
3103    ///   .with_from_id("proto::from")
3104    ///   .as_websocket_connect_record()
3105    ///   .build()
3106    ///   .to_json()
3107    /// # "#;
3108    /// # let record = rhai_rusp::eval_rusp::<String>(script).unwrap();
3109    /// # assert_eq!(record, "{\n  \"version\": \"1.3\",\n  \"to_id\": \"proto::to\",\n  \"from_id\": \"proto::from\",\n  \"payload_security\": \"PLAINTEXT\",\n  \"mac_signature\": [],\n  \"sender_cert\": [],\n  \"websocket_connect\": null\n}");
3110    /// ```
3111    ///
3112    /// This example will return a JSON output like:
3113    /// ```text
3114    /// {
3115    ///   "version": "1.3",
3116    ///   "to_id": "proto::to",
3117    ///   "from_id": "proto::from",
3118    ///   "payload_security": "PLAINTEXT",
3119    ///   "mac_signature": [],
3120    ///   "sender_cert": [],
3121    ///   "websocket_connect": null
3122    /// }
3123    /// ```
3124    ///
3125    /// # Errors
3126    ///
3127    /// This function will return `Err` containing a textual description of the encountered error if
3128    /// the serialization of the structure into JSON format fails.
3129    #[rhai_fn(global, name = "to_json", return_raw)]
3130    pub fn record_to_json(record: &mut Record) -> Result<String, Box<EvalAltResult>> {
3131        Ok(serde_json::to_string_pretty(&record).map_err(|e| e.to_string())?)
3132    }
3133
3134    /// Render a USP Body into a Rhai Map, this function is polymorphic in Rhai and available as `to_map()`
3135    /// ```
3136    /// // Rhai script
3137    /// # let script = r#"
3138    /// let body = rusp::get_builder().with_max_depth(1).with_params(["Device."]).build().to_map();
3139    /// body.Request
3140    /// # "#;
3141    /// # let msg = rhai_rusp::eval_rusp::<rhai::Map>(script).unwrap();
3142    /// ```
3143    ///
3144    /// This example will return a Rhai Map like:
3145    /// ```text
3146    /// #{"Get": #{"max_depth": 1, "param_paths": ["Device."]}}
3147    /// ```
3148    ///
3149    /// # Errors
3150    ///
3151    /// This function will return `Err` containing a textual description of the encountered error if
3152    /// the serialization of the structure into a Rhai map fails.
3153    #[rhai_fn(global, name = "to_map", return_raw)]
3154    pub fn body_to_map(body: &mut Body) -> Result<Dynamic, Box<EvalAltResult>> {
3155        rhai::serde::to_dynamic(body)
3156    }
3157
3158    /// Render a [`Msg`] into a Rhai Map, this function is polymorphic in Rhai and available as `to_map()`
3159    /// ```
3160    /// // Rhai script
3161    /// # let script = r#"
3162    /// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
3163    ///     .build();
3164    /// let msg = rusp::msg_builder()
3165    ///     .with_msg_id("Foo")
3166    ///     .with_body(body)
3167    ///     .build()
3168    ///     .to_map();
3169    /// msg.Header
3170    /// # "#;
3171    /// # let msg = rhai_rusp::eval_rusp::<rhai::Map>(script).unwrap();
3172    /// ```
3173    ///
3174    /// This example will return a Rhai Map like:
3175    /// ```text
3176    /// #{"msg_id": "Foo", "msg_type": "GET_SUPPORTED_PROTO"}
3177    /// ```
3178    ///
3179    /// # Errors
3180    ///
3181    /// This function will return `Err` containing a textual description of the encountered error if
3182    /// the serialization of the structure into a Rhai map fails.
3183    #[rhai_fn(global, name = "to_map", return_raw)]
3184    pub fn msg_to_map(msg: &mut Msg) -> Result<Dynamic, Box<EvalAltResult>> {
3185        rhai::serde::to_dynamic(msg)
3186    }
3187
3188    /// Render a [`Record`] into a Rhai Map, this function is polymorphic in Rhai and available as `to_map()`
3189    /// ```
3190    /// // Rhai script
3191    /// # let script = r#"
3192    /// rusp::record_builder()
3193    ///   .with_version("1.3")
3194    ///   .with_to_id("proto::to")
3195    ///   .with_from_id("proto::from")
3196    ///   .as_websocket_connect_record()
3197    ///   .build()
3198    ///   .to_map()
3199    /// # "#;
3200    /// # let record = rhai_rusp::eval_rusp::<rhai::Map>(script).unwrap();
3201    /// # assert_eq!(record.get("version").and_then(|v| v.clone().into_string().ok()), Some("1.3".into()));
3202    /// ```
3203    ///
3204    /// This example will return a Rhai map like:
3205    /// ```text
3206    /// #{"from_id": "proto::from", "mac_signature": [], "payload_security": "PLAINTEXT", "sender_cert": [], "to_id": "proto::to", "version": "1.3", "websocket_connect": ()}
3207    /// ```
3208    ///
3209    /// # Errors
3210    ///
3211    /// This function will return `Err` containing a textual description of the encountered error if
3212    /// the serialization of the structure into a Rhai map fails.
3213    #[rhai_fn(global, name = "to_map", return_raw)]
3214    pub fn record_to_map(record: &mut Record) -> Result<Dynamic, Box<EvalAltResult>> {
3215        rhai::serde::to_dynamic(record)
3216    }
3217
3218    /// Render a [`Msg`] into C string format
3219    ///
3220    /// # Errors
3221    ///
3222    /// This function will return `Err` containing a textual description of the encountered error if
3223    /// the serialization of the structure into a C string fails.
3224    #[rhai_fn(global, name = "to_c_string", return_raw)]
3225    pub fn msg_to_c_string(msg: &mut Msg) -> Result<String, Box<EvalAltResult>> {
3226        Ok(msg.to_c_str().map_err(|e| e.to_string())?)
3227    }
3228
3229    /// Render a [`Record`] into C string format
3230    ///
3231    /// # Errors
3232    ///
3233    /// This function will return `Err` containing a textual description of the encountered error if
3234    /// the serialization of the structure into a C string fails.
3235    #[rhai_fn(global, name = "to_c_string", return_raw)]
3236    pub fn record_to_c_string(record: &mut Record) -> Result<String, Box<EvalAltResult>> {
3237        Ok(record.to_c_str().map_err(|e| e.to_string())?)
3238    }
3239
3240    /// Render a [`Msg`] into C array format, this function is polymorphic in Rhai and available as `to_c_array()`
3241    /// ```
3242    /// // Rhai script
3243    /// # let script = r#"
3244    /// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
3245    ///     .build();
3246    /// rusp::msg_builder()
3247    ///     .with_msg_id("Foo")
3248    ///     .with_body(body)
3249    ///     .build()
3250    ///     .to_c_array()
3251    /// # "#;
3252    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
3253    /// # assert_eq!(msg, "unsigned int pb_len = 24;\nconst char pb[] = {\n  0x0a, 0x07, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x10, /* ____Foo_ */\n  0x11, 0x12, 0x0d, 0x0a, 0x0b, 0x4a, 0x09, 0x0a, /* _____J__ */\n  0x07, 0x31, 0x2e, 0x33, 0x2c, 0x31, 0x2e, 0x34, /* _1.3,1.4 */\n};\n");
3254    /// ```
3255    ///
3256    /// This example will return a string like:
3257    /// ```C
3258    /// unsigned int pb_len = 24;
3259    /// const char pb[] = {
3260    ///   0x0a, 0x07, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x10, /* ____Foo_ */
3261    ///   0x11, 0x12, 0x0d, 0x0a, 0x0b, 0x4a, 0x09, 0x0a, /* _____J__ */
3262    ///   0x07, 0x31, 0x2e, 0x33, 0x2c, 0x31, 0x2e, 0x34, /* _1.3,1.4 */
3263    /// };
3264    /// ```
3265    ///
3266    /// # Errors
3267    ///
3268    /// This function will return `Err` containing a textual description of the encountered error if
3269    /// the serialization of the structure into a C array fails.
3270    #[rhai_fn(global, name = "to_c_array", return_raw)]
3271    pub fn msg_to_c_array(msg: &mut Msg) -> Result<String, Box<EvalAltResult>> {
3272        Ok(msg.to_c_array().map_err(|e| e.to_string())?)
3273    }
3274
3275    /// Render a [`Msg`] into C array format with a custom variable name, this function is polymorphic in Rhai and available as `to_c_array()`
3276    /// ```
3277    /// // Rhai script
3278    /// # let script = r#"
3279    /// let body = rusp::getsupportedprotocol_builder("1.3,1.4")
3280    ///     .build();
3281    /// rusp::msg_builder()
3282    ///     .with_msg_id("Foo")
3283    ///     .with_body(body)
3284    ///     .build()
3285    ///     .to_c_array("msg")
3286    /// # "#;
3287    /// # let msg = rhai_rusp::eval_rusp::<String>(script).unwrap();
3288    /// # assert_eq!(msg, "unsigned int msg_len = 24;\nconst char msg[] = {\n  0x0a, 0x07, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x10, /* ____Foo_ */\n  0x11, 0x12, 0x0d, 0x0a, 0x0b, 0x4a, 0x09, 0x0a, /* _____J__ */\n  0x07, 0x31, 0x2e, 0x33, 0x2c, 0x31, 0x2e, 0x34, /* _1.3,1.4 */\n};\n");
3289    /// ```
3290    ///
3291    /// This example will return a string like:
3292    /// ```C
3293    /// unsigned int msg_len = 24;
3294    /// const char msg[] = {
3295    ///   0x0a, 0x07, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x10, /* ____Foo_ */
3296    ///   0x11, 0x12, 0x0d, 0x0a, 0x0b, 0x4a, 0x09, 0x0a, /* _____J__ */
3297    ///   0x07, 0x31, 0x2e, 0x33, 0x2c, 0x31, 0x2e, 0x34, /* _1.3,1.4 */
3298    /// };
3299    /// ```
3300    ///
3301    /// # Errors
3302    ///
3303    /// This function will return `Err` containing a textual description of the encountered error if
3304    /// the serialization of the structure into a C array fails.
3305    #[rhai_fn(global, name = "to_c_array", return_raw)]
3306    pub fn msg_to_c_array_custom(msg: &mut Msg, name: &str) -> Result<String, Box<EvalAltResult>> {
3307        Ok(msg.to_c_array_custom(name).map_err(|e| e.to_string())?)
3308    }
3309
3310    /// Render a [`Record`] into a C array variable, this function is polymorphic in Rhai and available as `to_c_array()`
3311    /// ```
3312    /// // Rhai script
3313    /// # let script = r#"
3314    /// rusp::record_builder()
3315    ///   .with_version("1.3")
3316    ///   .with_to_id("proto::to")
3317    ///   .with_from_id("proto::from")
3318    ///   .as_websocket_connect_record()
3319    ///   .build()
3320    ///   .to_c_array()
3321    /// # "#;
3322    /// # let record = rhai_rusp::eval_rusp::<String>(script).unwrap();
3323    /// # assert_eq!(record, "unsigned int pb_len = 31;\nconst char pb[] = {\n  0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x09, 0x70, /* __1.3__p */\n  0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x74, 0x6f, /* roto__to */\n  0x1a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, /* __proto_ */\n  0x3a, 0x66, 0x72, 0x6f, 0x6d, 0x4a, 0x00,       /* _fromJ_ */\n};\n");
3324    /// ```
3325    ///
3326    /// This example will return a String like:
3327    /// ```C
3328    /// unsigned int pb_len = 31;
3329    /// const char pb[] = {
3330    ///   0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x09, 0x70, /* __1.3__p */
3331    ///   0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x74, 0x6f, /* roto__to */
3332    ///   0x1a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, /* __proto_ */
3333    ///   0x3a, 0x66, 0x72, 0x6f, 0x6d, 0x4a, 0x00,       /* _fromJ_ */
3334    /// };
3335    /// ```
3336    ///
3337    /// # Errors
3338    ///
3339    /// This function will return `Err` containing a textual description of the encountered error if
3340    /// the serialization of the structure into a C array fails.
3341    #[rhai_fn(global, name = "to_c_array", return_raw)]
3342    pub fn record_to_c_array(record: &mut Record) -> Result<String, Box<EvalAltResult>> {
3343        Ok(record.to_c_array().map_err(|e| e.to_string())?)
3344    }
3345
3346    /// Render a [`Record`] into a C array variable with a custom name, this function is polymorphic in Rhai and available as `to_c_array()`
3347    /// ```
3348    /// // Rhai script
3349    /// # let script = r#"
3350    /// rusp::record_builder()
3351    ///   .with_version("1.3")
3352    ///   .with_to_id("proto::to")
3353    ///   .with_from_id("proto::from")
3354    ///   .as_websocket_connect_record()
3355    ///   .build()
3356    ///   .to_c_array("rec")
3357    /// # "#;
3358    /// # let record = rhai_rusp::eval_rusp::<String>(script).unwrap();
3359    /// # assert_eq!(record, "unsigned int rec_len = 31;\nconst char rec[] = {\n  0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x09, 0x70, /* __1.3__p */\n  0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x74, 0x6f, /* roto__to */\n  0x1a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, /* __proto_ */\n  0x3a, 0x66, 0x72, 0x6f, 0x6d, 0x4a, 0x00,       /* _fromJ_ */\n};\n");
3360    /// ```
3361    ///
3362    /// This example will return a String like:
3363    /// ```C
3364    /// unsigned int rec_len = 31;
3365    /// const char rec[] = {
3366    ///   0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x09, 0x70, /* __1.3__p */
3367    ///   0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x74, 0x6f, /* roto__to */
3368    ///   0x1a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, /* __proto_ */
3369    ///   0x3a, 0x66, 0x72, 0x6f, 0x6d, 0x4a, 0x00,       /* _fromJ_ */
3370    /// };
3371    /// ```
3372    ///
3373    /// # Errors
3374    ///
3375    /// This function will return `Err` containing a textual description of the encountered error if
3376    /// the serialization of the structure into a C array fails.
3377    #[rhai_fn(global, name = "to_c_array", return_raw)]
3378    pub fn record_to_c_array_custom(
3379        record: &mut Record,
3380        name: &str,
3381    ) -> Result<String, Box<EvalAltResult>> {
3382        Ok(record.to_c_array_custom(name).map_err(|e| e.to_string())?)
3383    }
3384
3385    /// Render a [`Msg`] into C array format and save it to the specified file
3386    ///
3387    /// # Errors
3388    ///
3389    /// This function will return `Err` containing a textual description of the encountered error
3390    /// if the serialization of the structure into a C array or the creation of the specified file
3391    /// fails.
3392    #[rhai_fn(global, name = "save_c_array", return_raw)]
3393    pub fn msg_save_c_array(msg: &mut Msg, filename: &str) -> Result<(), Box<EvalAltResult>> {
3394        let data = msg.to_c_array().map_err(|e| e.to_string())?;
3395        std::fs::write(filename, data).map_err(|e| e.to_string())?;
3396        Ok(())
3397    }
3398
3399    /// Render a [`Record`] into C array format and save it to the specified file
3400    ///
3401    /// # Errors
3402    ///
3403    /// This function will return `Err` containing a textual description of the encountered error
3404    /// if the serialization of the structure into a C array or the creation of the specified file
3405    /// fails.
3406    #[rhai_fn(global, name = "save_c_array", return_raw)]
3407    pub fn record_save_c_array(
3408        record: &mut Record,
3409        filename: &str,
3410    ) -> Result<(), Box<EvalAltResult>> {
3411        let data = record.to_c_array().map_err(|e| e.to_string())?;
3412        std::fs::write(filename, data).map_err(|e| e.to_string())?;
3413        Ok(())
3414    }
3415
3416    /// Render a [`Msg`] into Protobuf and print it to stdout
3417    ///
3418    /// # Errors
3419    ///
3420    /// This function will return `Err` containing a textual description of the encountered error
3421    /// if the serialization of the structure into Protobuf format fails.
3422    #[rhai_fn(global, name = "print_protobuf", return_raw)]
3423    pub fn msg_print_protobuf(msg: &mut Msg) -> Result<(), Box<EvalAltResult>> {
3424        std::io::stdout()
3425            .write_all(&msg.to_vec().map_err(|e| e.to_string())?)
3426            .map_err(|e| e.to_string())?;
3427        Ok(())
3428    }
3429
3430    /// Render a [`Record`] into Protobuf and print it to stdout
3431    ///
3432    /// # Errors
3433    ///
3434    /// This function will return `Err` containing a textual description of the encountered error
3435    /// if the serialization of the structure into Protobuf format fails.
3436    #[rhai_fn(global, name = "print_protobuf", return_raw)]
3437    pub fn record_print_protobuf(record: &mut Record) -> Result<(), Box<EvalAltResult>> {
3438        std::io::stdout()
3439            .write_all(&record.to_vec().map_err(|e| e.to_string())?)
3440            .map_err(|e| e.to_string())?;
3441        Ok(())
3442    }
3443
3444    /// Render a [`Msg`] into Protobuf and save it to the specified file
3445    ///
3446    /// # Errors
3447    ///
3448    /// This function will return `Err` containing a textual description of the encountered error
3449    /// if the serialization of the structure into Protobuf format or the creation of the specified file
3450    /// fails.
3451    #[rhai_fn(global, name = "save_protobuf", return_raw)]
3452    pub fn msg_save_protobuf(msg: &mut Msg, filename: &str) -> Result<(), Box<EvalAltResult>> {
3453        let data = msg.to_vec().map_err(|e| e.to_string())?;
3454        std::fs::File::create(filename)
3455            .and_then(|mut f| f.write_all(&data))
3456            .map_err(|e| e.to_string())?;
3457        Ok(())
3458    }
3459
3460    /// Render a [`Record`] into Protobuf and save it to the specified file
3461    ///
3462    /// # Errors
3463    ///
3464    /// This function will return `Err` containing a textual description of the encountered error
3465    /// if the serialization of the structure into Protobuf format or the creation of the specified file
3466    /// fails.
3467    #[rhai_fn(global, name = "save_protobuf", return_raw)]
3468    pub fn record_save_protobuf(
3469        record: &mut Record,
3470        filename: &str,
3471    ) -> Result<(), Box<EvalAltResult>> {
3472        let data = record.to_vec().map_err(|e| e.to_string())?;
3473        std::fs::File::create(filename)
3474            .and_then(|mut f| f.write_all(&data))
3475            .map_err(|e| e.to_string())?;
3476        Ok(())
3477    }
3478
3479    /// Extracts the [`Record`]'s payload. Returning [`Dynamic::UNIT`] for Records without payloads
3480    ///
3481    /// To avoid clones, this function leaves the used [`Record`] with an empty payload
3482    #[rhai_fn(global, name = "extract_msg")]
3483    pub fn record_extract_msg(record: &mut Record) -> Dynamic {
3484        match &mut record.record_type {
3485            OneOfrecord_type::session_context(ctx) => {
3486                let payload = ctx.payload_flatten();
3487                Dynamic::from_blob(mem::take(payload))
3488            }
3489            OneOfrecord_type::no_session_context(ctx) => {
3490                Dynamic::from_blob(mem::take(&mut ctx.payload))
3491            }
3492            _ => Dynamic::UNIT,
3493        }
3494    }
3495
3496    /// Parses a [`Msg`] from the provided Protobuf bytes
3497    ///
3498    /// # Errors
3499    ///
3500    /// This function will return `Err` when the deserialization of the structure from the Protobuf
3501    /// format fails
3502    #[rhai_fn(global, name = "parse_msg", return_raw)]
3503    pub fn parse_msg_protobuf(protobuf: &mut Blob) -> Result<Msg, Box<EvalAltResult>> {
3504        try_decode_msg(protobuf).map_err(|e| e.to_string().into())
3505    }
3506
3507    /// Read a [`Msg`] in Protobuf format from stdin. In Rhai this function is called `read_msg`.
3508    ///
3509    /// # Errors
3510    ///
3511    /// This function will return `Err` containing a textual description of the encountered error
3512    /// if the deserialization of the structure from Protobuf format fails.
3513    #[rhai_fn(global, name = "read_msg", return_raw)]
3514    pub fn read_msg_protobuf() -> Result<Msg, Box<EvalAltResult>> {
3515        let mut contents = Vec::new();
3516        std::io::stdin()
3517            .read_to_end(&mut contents)
3518            .map_err(|e| e.to_string())?;
3519        Ok(try_decode_msg(&contents).map_err(|e| e.to_string())?)
3520    }
3521
3522    /// Load a [`Msg`] from a Protobuf file. In Rhai this function is called `load_msg`
3523    ///
3524    /// # Errors
3525    ///
3526    /// This function will return `Err` containing a textual description of the encountered error
3527    /// if the file pointed to by the filename doesn't exist, is not readable or the
3528    /// deserialization of the structure from Protobuf format fails.
3529    #[rhai_fn(global, name = "load_msg", return_raw)]
3530    pub fn load_msg_protobuf(filename: &str) -> Result<Msg, Box<EvalAltResult>> {
3531        let mut contents = Vec::new();
3532        let _ = std::fs::File::open(filename)
3533            .map(|mut f| f.read_to_end(&mut contents))
3534            .map_err(|e| e.to_string())?;
3535        Ok(try_decode_msg(&contents).map_err(|e| e.to_string())?)
3536    }
3537
3538    /// Read a [`Record`] in Protobuf format from stdin. In Rhai this function is called `read_record`.
3539    /// ```
3540    /// // Rhai script
3541    /// # let script = r#"
3542    /// let record = rusp::read_record();
3543    /// record.to_string()
3544    /// # "#;
3545    /// ```
3546    ///
3547    /// # Errors
3548    ///
3549    /// This function will return `Err` containing a textual description of the encountered error
3550    /// if the deserialization of the structure from Protobuf format fails.
3551    #[rhai_fn(global, name = "read_record", return_raw)]
3552    pub fn read_record_protobuf() -> Result<Record, Box<EvalAltResult>> {
3553        let mut contents = Vec::new();
3554        std::io::stdin()
3555            .read_to_end(&mut contents)
3556            .map_err(|e| e.to_string())?;
3557        let record = try_decode_record(&contents).map_err(|e| e.to_string())?;
3558        if record.record_type == OneOfrecord_type::None {
3559            Err("Protobuf file doesn't contain a valid USP Record")?;
3560        }
3561        Ok(record)
3562    }
3563
3564    /// Load a [`Record`] from a Protobuf file, in Rhai this function is called `load_record`.
3565    /// ```
3566    /// // Rhai script
3567    /// # let script = r#"
3568    /// let record = rusp::load_record("test.pb");
3569    /// record.to_string()
3570    /// # "#;
3571    /// ```
3572    ///
3573    /// # Errors
3574    ///
3575    /// This function will return `Err` containing a textual description of the encountered error
3576    /// if the file pointed to by the filename doesn't exist, is not readable or the
3577    /// deserialization of the structure from Protobuf format fails.
3578    #[rhai_fn(global, name = "load_record", return_raw)]
3579    pub fn load_record_protobuf(filename: &str) -> Result<Record, Box<EvalAltResult>> {
3580        let mut contents = Vec::new();
3581        let _ = std::fs::File::open(filename)
3582            .map(|mut f| f.read_to_end(&mut contents))
3583            .map_err(|e| e.to_string())?;
3584        let record = try_decode_record(&contents).map_err(|e| e.to_string())?;
3585        if record.record_type == OneOfrecord_type::None {
3586            Err("Protobuf file doesn't contain a valid USP Record")?;
3587        }
3588        Ok(record)
3589    }
3590}
3591
3592def_package! {
3593    pub RuspPackage(module) {
3594        combine_with_exported_module!(module, "rusp", rhai_rusp);
3595        combine_with_exported_module!(module, "rusp", rhai_rusp_msg);
3596        combine_with_exported_module!(module, "rusp", rhai_rusp_record);
3597        combine_with_exported_module!(module, "rusp", rhai_rusp_add);
3598        combine_with_exported_module!(module, "rusp", rhai_rusp_addresp);
3599        combine_with_exported_module!(module, "rusp", rhai_rusp_delete);
3600        combine_with_exported_module!(module, "rusp", rhai_rusp_deleteresp);
3601        combine_with_exported_module!(module, "rusp", rhai_rusp_deregister);
3602        combine_with_exported_module!(module, "rusp", rhai_rusp_deregisterresp);
3603        combine_with_exported_module!(module, "rusp", rhai_rusp_error);
3604        combine_with_exported_module!(module, "rusp", rhai_rusp_get);
3605        combine_with_exported_module!(module, "rusp", rhai_rusp_getresp);
3606        combine_with_exported_module!(module, "rusp", rhai_rusp_getinstances);
3607        combine_with_exported_module!(module, "rusp", rhai_rusp_getinstancesresp);
3608        combine_with_exported_module!(module, "rusp", rhai_rusp_getsupportedprotocol);
3609        combine_with_exported_module!(module, "rusp", rhai_rusp_getsupportedprotocolresp);
3610        combine_with_exported_module!(module, "rusp", rhai_rusp_getsupporteddm);
3611        combine_with_exported_module!(module, "rusp", rhai_rusp_getsupporteddmresp);
3612        combine_with_exported_module!(module, "rusp", rhai_rusp_notify);
3613        combine_with_exported_module!(module, "rusp", rhai_rusp_notifyresp);
3614        combine_with_exported_module!(module, "rusp", rhai_rusp_operate);
3615        combine_with_exported_module!(module, "rusp", rhai_rusp_operateresp);
3616        combine_with_exported_module!(module, "rusp", rhai_rusp_register);
3617        combine_with_exported_module!(module, "rusp", rhai_rusp_registerresp);
3618        combine_with_exported_module!(module, "rusp", rhai_rusp_set);
3619        combine_with_exported_module!(module, "rusp", rhai_rusp_setresp);
3620    }
3621}