1use std::ops::{Deref, DerefMut};
4use std::future::Future;
5use std::borrow::Cow;
6use std::fmt::Debug;
7use std::sync::Arc;
8
9use crate::dev::{All, DevProxy, Named, NamedResult, ProxyTarget, ToNames, ToNamesNotAll, unexpected_len_err};
10use crate::error::{Error, ErrorKind, Result, reason};
11use crate::backend::{default_backend, Backend};
12use crate::prop::{FromProp, IntoProp};
13use crate::value::{Scalar, Spectrum};
14
15
16#[derive(Debug, PartialEq, Eq, Hash)]
18#[repr(transparent)]
19pub struct DatabaseProxy {
20 dev: DevProxy,
21}
22
23impl DatabaseProxy {
24
25 pub fn new_from_env() -> Self {
29 Self::new_from_env_with_backend(default_backend())
30 }
31
32 pub fn new(host: &str, port: u16) -> Self {
34 Self::new_with_backend(default_backend(), host, port)
35 }
36
37 pub fn new_from_env_with_backend(backend: Arc<dyn Backend>) -> Self {
39 Self {
40 dev: DevProxy::new_from_target_with_backend(backend, ProxyTarget::DatabaseFromEnv),
41 }
42 }
43
44 pub fn new_with_backend(backend: Arc<dyn Backend>, host: &str, port: u16) -> Self {
46 Self {
47 dev: DevProxy::new_from_target_with_backend(backend, ProxyTarget::DatabaseAt {
48 host: Arc::from(host),
49 port,
50 }),
51 }
52 }
53
54 pub(crate) fn from_dev(dev: &DevProxy) -> &DatabaseProxy {
56 unsafe { &*(dev as *const _ as *const DatabaseProxy) }
58 }
59
60 pub(crate) fn with_dev(dev: DevProxy) -> Self {
63 Self {
64 dev,
65 }
66 }
67
68 pub(crate) async fn host_and_port_async(&self) -> Result<(Arc<str>, u16)> {
72 let host_and_port = self.dev.database_host_and_port_async().await?;
73 Ok(host_and_port.expect("This should be defined if the target is a database"))
74 }
75
76 #[doc(alias = "DbInfo")]
79 pub async fn info_async(&self) -> Result<Spectrum<str>> {
80 self.command_async("DbInfo", ()).await
81 }
82
83 #[doc(alias = "DbInfo")]
85 pub fn info(&self) -> Result<Spectrum<str>> {
86 self.block_on(self.info_async())?
87 }
88
89 #[doc(alias = "DbAddDevice")]
92 pub async fn add_dev_async(&self, name: &str, class: &str, server: &str) -> Result<()> {
93 self.command_async("DbAddDevice", [server, name, class]).await
94 }
95
96 #[doc(alias = "DbAddDevice")]
98 pub fn add_dev(&self, name: &str, class: &str, server: &str) -> Result<()> {
99 self.block_on(self.add_dev_async(name, class, server))?
100 }
101
102 #[doc(alias = "DbDeleteDevice")]
103 pub async fn delete_dev_async(&self, name: &str) -> Result<()> {
104 self.command_async("DbDeleteDevice", name).await
105 }
106
107 #[doc(alias = "DbDeleteDevice")]
109 pub fn delete_dev(&self, name: &str) -> Result<()> {
110 self.block_on(self.delete_dev_async(name))?
111 }
112
113 #[doc(alias = "DbAddServer")]
118 pub async fn add_server_async(&self, server: &str, devs: &[(&str, &str)]) -> Result<()> {
119 let mut args = Vec::with_capacity(1 + devs.len() * 2);
120 args.push(server);
121 args.extend(devs.iter().flat_map(|&(name, class)| [name, class]));
122 self.command_async("DbAddServer", &args[..]).await
123 }
124
125 #[doc(alias = "DbAddServer")]
127 pub fn add_server(&self, server: &str, devs: &[(&str, &str)]) -> Result<()> {
128 self.block_on(self.add_server_async(server, devs))?
129 }
130
131 #[doc(alias = "DbDeleteServer")]
133 pub async fn delete_server_async(&self, server: &str) -> Result<()> {
134 self.command_async("DbDeleteServer", server).await
135 }
136
137 #[doc(alias = "DbDeleteServer")]
139 pub fn delete_server(&self, server: &str) -> Result<()> {
140 self.block_on(self.delete_server_async(server))?
141 }
142
143 #[doc(alias = "DbRenameServer")]
144 pub async fn rename_server_async(&self, name: &str, new_name: &str) -> Result<()> {
145 self.command_async("DbRenameServer", [name, new_name]).await
146 }
147
148 #[doc(alias = "DbRenameServer")]
150 pub fn rename_server(&self, name: &str, new_name: &str) -> Result<()> {
151 self.block_on(self.rename_server_async(name, new_name))?
152 }
153
154 #[doc(alias = "DbGetDeviceClassList")]
158 pub async fn list_server_dev_async(&self, server: &str) -> Result<Vec<Named<Scalar<str>>>> {
159
160 let flat: Spectrum<str> = self.command_async("DbGetDeviceClassList", server).await?;
161
162 let mut pairs = Vec::with_capacity(flat.len() / 2);
163 let mut index = 0;
164
165 while let Some(dev_name) = flat.get_scalar([index]) {
166 let Some(class_name) = flat.get_scalar([index + 1]) else {
167 return Err(Error::new(ErrorKind::InvalidData)
168 .with_append_description("The answer should be a string spectrum of device/class pairs")
169 .with_append_description(format_args!("the device {:?} has no class", dev_name.value())));
170 };
171 pairs.push(Named::new(dev_name, class_name));
172 index += 2;
173 }
174
175 Ok(pairs)
176
177 }
178
179 #[doc(alias = "DbGetDeviceClassList")]
181 pub fn list_server_dev(&self, server: &str) -> Result<Vec<Named<Scalar<str>>>> {
182 self.block_on(self.list_server_dev_async(server))?
183 }
184
185 #[doc(alias = "DbGetDeviceWideList")]
190 pub async fn list_dev_async(&self, filter: &str) -> Result<Spectrum<str>> {
191 self.command_async("DbGetDeviceWideList", filter).await
192 }
193
194 #[doc(alias = "DbGetDeviceWideList")]
196 pub fn list_dev(&self, filter: &str) -> Result<Spectrum<str>> {
197 self.block_on(self.list_dev_async(filter))?
198 }
199
200 #[doc(alias = "DbGetDeviceMemberList")]
203 pub async fn list_dev_member_async(&self, filter: &str) -> Result<Spectrum<str>> {
204 self.command_async("DbGetDeviceMemberList", filter).await
205 }
206
207 #[doc(alias = "DbGetDeviceMemberList")]
209 pub fn list_dev_member(&self, filter: &str) -> Result<Spectrum<str>> {
210 self.block_on(self.list_dev_member_async(filter))?
211 }
212
213 #[doc(alias = "DbGetDeviceFamilyList")]
216 pub async fn list_dev_family_async(&self, filter: &str) -> Result<Spectrum<str>> {
217 self.command_async("DbGetDeviceFamilyList", filter).await
218 }
219
220 #[doc(alias = "DbGetDeviceFamilyList")]
222 pub fn list_dev_family(&self, filter: &str) -> Result<Spectrum<str>> {
223 self.block_on(self.list_dev_family_async(filter))?
224 }
225
226 #[doc(alias = "DbGetDeviceDomainList")]
229 pub async fn list_dev_domain_async(&self, filter: &str) -> Result<Spectrum<str>> {
230 self.command_async("DbGetDeviceDomainList", filter).await
231 }
232
233 #[doc(alias = "DbGetDeviceDomainList")]
235 pub fn list_dev_domain(&self, filter: &str) -> Result<Spectrum<str>> {
236 self.block_on(self.list_dev_domain_async(filter))?
237 }
238
239 #[doc(alias = "DbExportDevice")]
242 pub async fn export_dev_async(&self, info: ExportDevInfo<'_>) -> Result<()> {
243 self.command_async("DbExportDevice", data_from_export_dev_info(&[info][..])).await
244 }
245
246 #[doc(alias = "DbExportDevice")]
248 pub fn export_dev(&self, info: ExportDevInfo<'_>) -> Result<()> {
249 self.block_on(self.export_dev_async(info))?
250 }
251
252 #[doc(alias = "DbUnExportDevice")]
253 pub async fn unexport_dev_async(&self, dev_name: &str) -> Result<()> {
254 self.command_async("DbUnExportDevice", dev_name).await
255 }
256
257 #[doc(alias = "DbUnExportDevice")]
259 pub fn unexport_dev(&self, dev_name: &str) -> Result<()> {
260 self.block_on(self.unexport_dev_async(dev_name))?
261 }
262
263 #[doc(alias = "DbExportServer")]
264 pub async fn export_server_async(&self, infos: &[ExportDevInfo<'_>]) -> Result<()> {
265 self.command_async("DbExportServer", data_from_export_dev_info(infos)).await
266 }
267
268 #[doc(alias = "DbExportServer")]
270 pub fn export_server(&self, infos: &[ExportDevInfo<'_>]) -> Result<()> {
271 self.block_on(self.export_server_async(infos))?
272 }
273
274 #[doc(alias = "DbUnExportServer")]
275 pub async fn unexport_server_async(&self, server: &str) -> Result<()> {
276 self.command_async("DbUnExportServer", server).await
277 }
278
279 #[doc(alias = "DbUnExportServer")]
281 pub fn unexport_server(&self, server: &str) -> Result<()> {
282 self.block_on(self.unexport_server_async(server))?
283 }
284
285 #[doc(alias = "DbGetDeviceExportedList")]
288 pub async fn list_exported_dev_async(&self, filter: &str) -> Result<Spectrum<str>> {
289 self.command_async("DbGetDeviceExportedList", filter).await
290 }
291
292 #[doc(alias = "DbGetDeviceExportedList")]
294 pub fn list_exported_dev(&self, filter: &str) -> Result<Spectrum<str>> {
295 self.block_on(self.list_exported_dev_async(filter))?
296 }
297
298 #[doc(alias = "DbImportDevice")]
301 pub async fn import_dev_async(&self, dev_name: &str) -> Result<ImportDevInfo> {
302
303 let (
304 [exported, pid],
305 svalue,
306 ) = match self.command_async("DbImportDevice", dev_name).await.and_then(long2_string) {
307 Ok(ret) => ret,
308 Err(err) => {
309 if let ErrorKind::Reason(reason::DB_DeviceNotDefined) = err.kind() {
310 return Err(Error::new(ErrorKind::DevNotFound).with_parent(err));
311 } else {
312 return Err(err);
313 }
314 }
315 };
316
317 if svalue.len() != 5 && svalue.len() != 6 {
318 return Err(Error::new(ErrorKind::InvalidData)
319 .with_append_description("The strings of the answer should be 5 or 6")
320 .with_append_description(format_args!("{svalue:?}")));
321 }
322
323 let field = |index| svalue.get_scalar([index]).unwrap();
325
326 Ok(ImportDevInfo {
327 name: field(0),
328 itr: field(1),
329 host: field(4),
330 version: field(2),
331 server: field(3),
332 class: svalue.get_scalar([5]),
333 exported: exported == 1,
334 pid,
335 })
336
337 }
338
339 #[doc(alias = "DbImportDevice")]
341 pub fn import_dev(&self, dev_name: &str) -> Result<ImportDevInfo> {
342 self.block_on(self.import_dev_async(dev_name))?
343 }
344
345 #[doc(alias = "DbGetDeviceInfo")]
348 pub async fn get_dev_info_async(&self, dev_name: &str) -> Result<DevInfo> {
349
350 let (
351 [exported, pid],
352 svalue,
353 ) = match self.command_async("DbGetDeviceInfo", dev_name).await.and_then(long2_string) {
354 Ok(ret) => ret,
355 Err(err) => {
356 if let ErrorKind::Reason(reason::DB_DeviceNotDefined) = err.kind() {
357 return Err(Error::new(ErrorKind::DevNotFound).with_parent(err));
358 } else {
359 return Err(err);
360 }
361 }
362 };
363
364 if svalue.len() != 7 && svalue.len() != 8 {
365 return Err(Error::new(ErrorKind::InvalidData)
366 .with_append_description("The strings of the answer should be 7 or 8")
367 .with_append_description(format_args!("{svalue:?}")));
368 }
369
370 let field = |index| svalue.get_scalar([index]).unwrap();
372
373 Ok(DevInfo {
374 name: field(0),
375 itr: field(1),
376 host: Some(field(4)).filter(|host| host.value() != "nada"),
377 version: field(2),
378 server: field(3),
379 class: svalue.get_scalar([7]),
380 last_exported: Some(field(5)).filter(|time| time.value() != "?"),
381 last_unexported: Some(field(6)).filter(|time| time.value() != "?"),
382 exported: exported == 1,
383 pid: Some(pid).filter(|&pid| pid != 0),
384 })
385
386 }
387
388 #[doc(alias = "DbGetDeviceInfo")]
390 pub fn get_dev_info(&self, dev_name: &str) -> Result<DevInfo> {
391 self.block_on(self.get_dev_info_async(dev_name))?
392 }
393
394 #[doc(alias = "DbGetDeviceAlias")]
398 pub async fn get_dev_alias_async(&self, dev_name: &str) -> Result<Option<Scalar<str>>> {
399 match self.command_async::<_, Scalar<str>>("DbGetDeviceAlias", dev_name).await {
400 Ok(ret) => Ok(Some(ret)),
401 Err(err) => {
402 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
403 Ok(None)
404 } else {
405 Err(err)
406 }
407 }
408 }
409 }
410
411 #[doc(alias = "DbGetDeviceAlias")]
413 pub fn get_dev_alias(&self, dev_name: &str) -> Result<Option<Scalar<str>>> {
414 self.block_on(self.get_dev_alias_async(dev_name))?
415 }
416
417 #[doc(alias = "DbGetAliasDevice")]
419 pub async fn resolve_dev_alias_async(&self, alias: &str) -> Result<Scalar<str>> {
420 match self.command_async("DbGetAliasDevice", alias).await {
421 Ok(ret) => Ok(ret),
422 Err(err) => {
423 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
424 Err(Error::new(ErrorKind::AliasNotFound).with_parent(err))
425 } else {
426 Err(err)
427 }
428 }
429 }
430 }
431
432 #[doc(alias = "DbGetAliasDevice")]
434 pub fn resolve_dev_alias(&self, alias: &str) -> Result<Scalar<str>> {
435 self.block_on(self.resolve_dev_alias_async(alias))?
436 }
437
438 #[doc(alias = "DbGetAliasDevice")]
440 pub async fn list_dev_aliases_async(&self, filter: &str) -> Result<Spectrum<str>> {
441 self.command_async("DbGetAliasDevice", filter).await
442 }
443
444 #[doc(alias = "DbGetAliasDevice")]
446 pub fn list_dev_aliases(&self, filter: &str) -> Result<Spectrum<str>> {
447 self.block_on(self.list_dev_aliases_async(filter))?
448 }
449
450 #[doc(alias = "DbGetAttributeAlias")]
454 pub async fn get_attr_alias_async(&self, attr_name: &str) -> Result<Option<Scalar<str>>> {
455 match self.command_async::<_, Scalar<str>>("DbGetAttributeAlias", attr_name).await {
456 Ok(ret) => Ok(Some(ret)),
457 Err(err) => {
458 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
459 Ok(None)
460 } else {
461 Err(err)
462 }
463 }
464 }
465 }
466
467 #[doc(alias = "DbGetAttributeAlias")]
469 pub fn get_attr_alias(&self, attr_name: &str) -> Result<Option<Scalar<str>>> {
470 self.block_on(self.get_attr_alias_async(attr_name))?
471 }
472
473 #[doc(alias = "DbGetAliasAttribute")]
474 pub async fn resolve_attr_alias_async(&self, alias: &str) -> Result<Scalar<str>> {
475 match self.command_async("DbGetAliasAttribute", alias).await {
476 Ok(ret) => Ok(ret),
477 Err(err) => {
478 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
479 Err(Error::new(ErrorKind::AliasNotFound).with_parent(err))
480 } else {
481 Err(err)
482 }
483 }
484 }
485 }
486
487 #[doc(alias = "DbGetAliasAttribute")]
489 pub fn resolve_attr_alias(&self, alias: &str) -> Result<Scalar<str>> {
490 self.block_on(self.resolve_attr_alias_async(alias))?
491 }
492
493 #[doc(alias = "DbGetAttributeAliasList")]
495 pub async fn list_attr_aliases_async(&self, filter: &str) -> Result<Spectrum<str>> {
496 self.command_async("DbGetAttributeAliasList", filter).await
497 }
498
499 #[doc(alias = "DbGetAttributeAliasList")]
501 pub fn list_attr_aliases(&self, filter: &str) -> Result<Spectrum<str>> {
502 self.block_on(self.list_attr_aliases_async(filter))?
503 }
504
505 #[doc(alias = "DbGetPropertyList")]
508 pub async fn list_free_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
509 self.command_async("DbGetPropertyList", [obj_name, filter]).await
510 }
511
512 #[doc(alias = "DbGetPropertyList")]
513 pub fn list_free_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
514 self.block_on(self.list_free_prop_async(obj_name, filter))?
515 }
516
517 #[doc(alias = "DbGetClassPropertyList")]
520 #[doc(alias = "DbGetClassPropertyListWildcard")]
521 pub async fn list_class_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
522 if filter == "*" {
523 self.command_async("DbGetClassPropertyList", [obj_name]).await
524 } else {
525 self.command_async("DbGetClassPropertyListWildcard", [obj_name, filter]).await
526 }
527 }
528
529 #[doc(alias = "DbGetClassPropertyList")]
530 #[doc(alias = "DbGetClassPropertyListWildcard")]
531 pub fn list_class_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
532 self.block_on(self.list_class_prop_async(obj_name, filter))?
533 }
534
535 #[doc(alias = "DbGetDevicePropertyList")]
538 pub async fn list_dev_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
539 self.command_async("DbGetDevicePropertyList", [obj_name, filter]).await
540 }
541
542 #[doc(alias = "DbGetDevicePropertyList")]
543 pub fn list_dev_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
544 self.block_on(self.list_dev_prop_async(obj_name, filter))?
545 }
546
547 pub(crate) async fn get_raw_prop_async(&self,
556 commands: PropCommands,
557 obj_name: &str,
558 params: Option<Spectrum<str>>,
559 ) -> Result<get_prop::PropReply> {
560
561 let params = match params {
562 Some(params) => params,
563 None => {
564 let list_params = [obj_name, "*"];
565 let list_params = if commands.list_wildcard { &list_params[..] } else { &list_params[0..1] };
566 let names: Spectrum<str> = self.command_async(commands.list, list_params).await?;
567 prop_params(obj_name, names.iter())
568 }
569 };
570
571 let names = params.slice(1..);
572
573 if names.len() == 0 {
578 return Ok(get_prop::PropReply::empty());
579 }
580
581 let listing: Spectrum<str> = self.command_async(commands.get, params).await?;
582 get_prop::PropReply::new(obj_name, listing, names)
583
584 }
585
586 fn get_any_prop_async<Spec, Names: ToNames>(&self,
588 commands: PropCommands,
589 obj_name: &str,
590 names: Names,
591 ) -> impl Future<Output = Result<Spec::Output>> + Send
592 where
593 Spec: GetPropSpec<Names>,
594 {
595 let params = names.iter_names().map(|names| prop_params(obj_name, names));
596 async move {
597 let mut reply = self.get_raw_prop_async(commands, obj_name, params).await?;
598 Spec::collect(&mut reply)
599 }
600 }
601
602 #[doc(alias = "DbGetProperty")]
607 pub fn get_free_prop_async<Spec, Names: ToNames>(&self, obj_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
608 where
609 Spec: GetPropSpec<Names>,
610 {
611 self.get_any_prop_async::<Spec, Names>(PropCommands::FREE, obj_name, names)
612 }
613
614 #[doc(alias = "DbGetProperty")]
616 pub fn get_free_prop<Spec, Names: ToNames>(&self, obj_name: &str, names: Names) -> Result<Spec::Output>
617 where
618 Spec: GetPropSpec<Names>,
619 {
620 self.block_on(self.get_free_prop_async::<Spec, Names>(obj_name, names))?
621 }
622
623 #[doc(alias = "DbGetClassProperty")]
628 pub fn get_class_prop_async<Spec, Names: ToNames>(&self, class_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
629 where
630 Spec: GetPropSpec<Names>,
631 {
632 self.get_any_prop_async::<Spec, Names>(PropCommands::CLASS, class_name, names)
633 }
634
635 #[doc(alias = "DbGetClassProperty")]
637 pub fn get_class_prop<Spec, Names: ToNames>(&self, class_name: &str, names: Names) -> Result<Spec::Output>
638 where
639 Spec: GetPropSpec<Names>,
640 {
641 self.block_on(self.get_class_prop_async::<Spec, Names>(class_name, names))?
642 }
643
644 #[doc(alias = "DbGetDeviceProperty")]
668 pub fn get_dev_prop_async<Spec, Names: ToNames>(&self, dev_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
669 where
670 Spec: GetPropSpec<Names>,
671 {
672 self.get_any_prop_async::<Spec, Names>(PropCommands::DEV, dev_name, names)
673 }
674
675 #[doc(alias = "DbGetDeviceProperty")]
677 pub fn get_dev_prop<Spec, Names: ToNames>(&self, dev_name: &str, names: Names) -> Result<Spec::Output>
678 where
679 Spec: GetPropSpec<Names>,
680 {
681 self.block_on(self.get_dev_prop_async::<Spec, Names>(dev_name, names))?
682 }
683
684 pub(crate) async fn prop_command_async(&self, cmd_name: &'static str, params: Spectrum<str>) -> Result<()> {
689 self.command_async(cmd_name, params).await
690 }
691
692 #[doc(alias = "DbPutProperty")]
697 pub fn set_free_prop_async<'a, Spec>(&self, obj_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
698 where
699 Spec: SetPropSpec<'a>,
700 {
701 self.prop_command_async("DbPutProperty", prop_params(obj_name, set_prop_params(spec).iter().map(|param| &**param)))
702 }
703
704 #[doc(alias = "DbPutProperty")]
706 pub fn set_free_prop<'a, Spec>(&self, obj_name: &'a str, spec: Spec) -> Result<()>
707 where
708 Spec: SetPropSpec<'a>,
709 {
710 self.block_on(self.set_free_prop_async(obj_name, spec))?
711 }
712
713 #[doc(alias = "DbPutClassProperty")]
718 pub fn set_class_prop_async<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
719 where
720 Spec: SetPropSpec<'a>,
721 {
722 self.prop_command_async("DbPutClassProperty", prop_params(class_name, set_prop_params(spec).iter().map(|param| &**param)))
723 }
724
725 #[doc(alias = "DbPutClassProperty")]
727 pub fn set_class_prop<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> Result<()>
728 where
729 Spec: SetPropSpec<'a>,
730 {
731 self.block_on(self.set_class_prop_async(class_name, spec))?
732 }
733
734 #[doc(alias = "DbPutDeviceProperty")]
752 pub fn set_dev_prop_async<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
753 where
754 Spec: SetPropSpec<'a>,
755 {
756 self.prop_command_async("DbPutDeviceProperty", prop_params(dev_name, set_prop_params(spec).iter().map(|param| &**param)))
757 }
758
759 #[doc(alias = "DbPutDeviceProperty")]
761 pub fn set_dev_prop<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> Result<()>
762 where
763 Spec: SetPropSpec<'a>,
764 {
765 self.block_on(self.set_dev_prop_async(dev_name, spec))?
766 }
767
768 #[doc(alias = "DbDeleteProperty")]
773 pub fn del_obj_prop_async<Names: ToNamesNotAll>(&self, obj_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
774 self.prop_command_async("DbDeleteProperty", prop_params(obj_name, names.iter_names_not_all()))
775 }
776
777 #[doc(alias = "DbDeleteProperty")]
779 pub fn del_obj_prop<Names: ToNamesNotAll>(&self, obj_name: &str, names: Names) -> Result<()> {
780 self.block_on(self.del_obj_prop_async(obj_name, names))?
781 }
782
783 #[doc(alias = "DbDeleteClassProperty")]
788 pub fn del_class_prop_async<Names: ToNamesNotAll>(&self, class_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
789 self.prop_command_async("DbDeleteClassProperty", prop_params(class_name, names.iter_names_not_all()))
790 }
791
792 #[doc(alias = "DbDeleteClassProperty")]
794 pub fn del_class_prop<Names: ToNamesNotAll>(&self, class_name: &str, names: Names) -> Result<()> {
795 self.block_on(self.del_class_prop_async(class_name, names))?
796 }
797
798 #[doc(alias = "DbDeleteDeviceProperty")]
811 pub fn del_dev_prop_async<Names: ToNamesNotAll>(&self, dev_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
812 self.prop_command_async("DbDeleteDeviceProperty", prop_params(dev_name, names.iter_names_not_all()))
813 }
814
815 #[doc(alias = "DbDeleteDeviceProperty")]
817 pub fn del_dev_prop<Names: ToNamesNotAll>(&self, dev_name: &str, names: Names) -> Result<()> {
818 self.block_on(self.del_dev_prop_async(dev_name, names))?
819 }
820
821 pub(crate) async fn get_raw_attr_prop_async(&self,
834 commands: AttrPropCommands,
835 obj_name: &str,
836 params: Option<Spectrum<str>>,
837 prop_names: Option<Spectrum<str>>,
838 ) -> Result<get_prop::AttrPropReply> {
839
840 let params = match params {
841 Some(params) => params,
842 None => {
843 let attr_names: Spectrum<str> = self.command_async(commands.list, [obj_name, "*"]).await?;
844 prop_params(obj_name, attr_names.iter())
845 }
846 };
847
848 let attr_names = params.slice(1..);
850
851 if attr_names.is_empty() {
854 return Ok(get_prop::AttrPropReply::empty());
855 }
856
857 let listing: Spectrum<str> = self.command_async(commands.get, params).await?;
858 get_prop::AttrPropReply::new(obj_name, listing, attr_names, prop_names)
859
860 }
861
862 fn get_any_attr_prop_async<Spec, AttrNames, Names>(&self,
865 commands: AttrPropCommands,
866 obj_name: &str,
867 attr_names: AttrNames,
868 prop_names: Names,
869 ) -> impl Future<Output = Result<Spec::Output>> + Send
870 where
871 Spec: GetAttrPropSpec<AttrNames, Names>,
872 AttrNames: ToNames,
873 Names: ToNames,
874 {
875 let params = attr_names.iter_names().map(|attr_names| prop_params(obj_name, attr_names));
876 let prop_names = prop_names.to_names();
877 async move {
878 let mut reply = self.get_raw_attr_prop_async(commands, obj_name, params, prop_names).await?;
879 Spec::collect(&mut reply)
880 }
881 }
882
883 #[doc(alias = "DbGetClassAttributeProperty2")]
889 pub fn get_class_attr_prop_async<Spec, AttrNames, Names>(&self, class_name: &str, attr_names: AttrNames, prop_names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
890 where
891 Spec: GetAttrPropSpec<AttrNames, Names>,
892 AttrNames: ToNames,
893 Names: ToNames,
894 {
895 self.get_any_attr_prop_async::<Spec, AttrNames, Names>(AttrPropCommands::CLASS, class_name, attr_names, prop_names)
896 }
897
898 #[doc(alias = "DbGetClassAttributeProperty2")]
901 pub fn get_class_attr_prop<Spec, AttrNames, Names>(&self, class_name: &str, attr_names: AttrNames, prop_names: Names) -> Result<Spec::Output>
902 where
903 Spec: GetAttrPropSpec<AttrNames, Names>,
904 AttrNames: ToNames,
905 Names: ToNames,
906 {
907 self.block_on(self.get_class_attr_prop_async::<Spec, AttrNames, Names>(class_name, attr_names, prop_names))?
908 }
909
910 #[doc(alias = "DbGetDeviceAttributeProperty2")]
935 pub fn get_dev_attr_prop_async<Spec, AttrNames, Names>(&self, dev_name: &str, attr_names: AttrNames, prop_names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
936 where
937 Spec: GetAttrPropSpec<AttrNames, Names>,
938 AttrNames: ToNames,
939 Names: ToNames,
940 {
941 self.get_any_attr_prop_async::<Spec, AttrNames, Names>(AttrPropCommands::DEV, dev_name, attr_names, prop_names)
942 }
943
944 #[doc(alias = "DbGetDeviceAttributeProperty2")]
947 pub fn get_dev_attr_prop<Spec, AttrNames, Names>(&self, dev_name: &str, attr_names: AttrNames, prop_names: Names) -> Result<Spec::Output>
948 where
949 Spec: GetAttrPropSpec<AttrNames, Names>,
950 AttrNames: ToNames,
951 Names: ToNames,
952 {
953 self.block_on(self.get_dev_attr_prop_async::<Spec, AttrNames, Names>(dev_name, attr_names, prop_names))?
954 }
955
956 #[doc(alias = "DbPutClassAttributeProperty2")]
961 pub fn set_class_attr_prop_async<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
962 where
963 Spec: SetAttrPropSpec<'a>,
964 {
965 self.prop_command_async("DbPutClassAttributeProperty2", attr_prop_params(class_name, spec))
966 }
967
968 #[doc(alias = "DbPutClassAttributeProperty2")]
971 pub fn set_class_attr_prop<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> Result<()>
972 where
973 Spec: SetAttrPropSpec<'a>,
974 {
975 self.block_on(self.set_class_attr_prop_async(class_name, spec))?
976 }
977
978 #[doc(alias = "DbPutDeviceAttributeProperty2")]
994 pub fn set_dev_attr_prop_async<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
995 where
996 Spec: SetAttrPropSpec<'a>,
997 {
998 self.prop_command_async("DbPutDeviceAttributeProperty2", attr_prop_params(dev_name, spec))
999 }
1000
1001 #[doc(alias = "DbPutDeviceAttributeProperty2")]
1004 pub fn set_dev_attr_prop<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> Result<()>
1005 where
1006 Spec: SetAttrPropSpec<'a>,
1007 {
1008 self.block_on(self.set_dev_attr_prop_async(dev_name, spec))?
1009 }
1010
1011 #[doc(alias = "DbDeleteClassAttributeProperty")]
1016 pub fn del_class_attr_prop_async<Names: ToNamesNotAll>(&self, class_name: &str, attr_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
1017 let params = prop_params(class_name, Some(attr_name).into_iter().chain(names.iter_names_not_all()));
1018 self.prop_command_async("DbDeleteClassAttributeProperty", params)
1019 }
1020
1021 #[doc(alias = "DbDeleteClassAttributeProperty")]
1024 pub fn del_class_attr_prop<Names: ToNamesNotAll>(&self, class_name: &str, attr_name: &str, names: Names) -> Result<()> {
1025 self.block_on(self.del_class_attr_prop_async(class_name, attr_name, names))?
1026 }
1027
1028 #[doc(alias = "DbDeleteDeviceAttributeProperty")]
1040 pub fn del_dev_attr_prop_async<Names: ToNamesNotAll>(&self, dev_name: &str, attr_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
1041 let params = prop_params(dev_name, Some(attr_name).into_iter().chain(names.iter_names_not_all()));
1042 self.prop_command_async("DbDeleteDeviceAttributeProperty", params)
1043 }
1044
1045 #[doc(alias = "DbDeleteDeviceAttributeProperty")]
1048 pub fn del_dev_attr_prop<Names: ToNamesNotAll>(&self, dev_name: &str, attr_name: &str, names: Names) -> Result<()> {
1049 self.block_on(self.del_dev_attr_prop_async(dev_name, attr_name, names))?
1050 }
1051
1052 }
1090
1091impl Clone for DatabaseProxy {
1093 fn clone(&self) -> Self {
1094 Self { dev: self.dev.clone() }
1095 }
1096}
1097
1098impl Deref for DatabaseProxy {
1099 type Target = DevProxy;
1100 fn deref(&self) -> &Self::Target {
1101 &self.dev
1102 }
1103}
1104
1105impl DerefMut for DatabaseProxy {
1106 fn deref_mut(&mut self) -> &mut Self::Target {
1107 &mut self.dev
1108 }
1109}
1110
1111#[derive(Debug, Clone)]
1117pub struct ExportDevInfo<'a> {
1118 pub name: Cow<'a, str>,
1119 pub itr: Cow<'a, str>,
1120 pub host: Cow<'a, str>,
1121 pub version: Cow<'a, str>,
1122 pub pid: i32,
1123}
1124
1125fn data_from_export_dev_info(infos: &[ExportDevInfo<'_>]) -> Spectrum<str> {
1126
1127 let mut vec = Vec::with_capacity(infos.len() * 5);
1128
1129 for info in infos {
1130 vec.push(Cow::Borrowed(&*info.name));
1131 vec.push(Cow::Borrowed(&*info.itr));
1132 vec.push(Cow::Borrowed(&*info.host));
1133 vec.push(Cow::Owned(format!("{}", info.pid)));
1134 vec.push(Cow::Borrowed(&*info.version));
1135 }
1136
1137 Spectrum::from(&vec[..])
1138
1139}
1140
1141fn long2_string((longs, strings): (Spectrum<i32>, Spectrum<str>)) -> Result<([i32; 2], Spectrum<str>)> {
1144 let longs = <[i32; 2]>::try_from(longs.as_slice())
1145 .map_err(|_| Error::new(ErrorKind::InvalidData)
1146 .with_append_description("The longs of the answer should be 2")
1147 .with_append_description(format_args!("{longs:?}")))?;
1148 Ok((longs, strings))
1149}
1150
1151#[derive(Debug, Clone)]
1153pub struct ImportDevInfo {
1154 pub name: Scalar<str>,
1156 pub itr: Scalar<str>,
1158 pub host: Scalar<str>,
1160 pub version: Scalar<str>,
1162 pub server: Scalar<str>,
1164 pub class: Option<Scalar<str>>,
1166 pub exported: bool,
1168 pub pid: i32,
1170}
1171
1172#[derive(Debug, Clone)]
1173pub struct DevInfo {
1174 pub name: Scalar<str>,
1176 pub itr: Scalar<str>,
1178 pub host: Option<Scalar<str>>,
1180 pub version: Scalar<str>,
1182 pub server: Scalar<str>,
1184 pub class: Option<Scalar<str>>,
1186 pub last_exported: Option<Scalar<str>>, pub last_unexported: Option<Scalar<str>>, pub exported: bool,
1190 pub pid: Option<i32>,
1192}
1193
1194pub(crate) fn set_prop_params<'a, Spec: SetPropSpec<'a>>(spec: Spec) -> Vec<Cow<'a, str>> {
1207 let mut builder = set_prop::Builder::new();
1208 spec.push_to_builder(&mut builder);
1209 builder.finalize()
1210}
1211
1212pub(crate) fn prop_params<'a>(obj_name: &'a str, rest: impl Iterator<Item = &'a str>) -> Spectrum<str> {
1215 Spectrum::from_strs(Some(obj_name).into_iter().chain(rest)).expect("property parameters of more than 4 GiB")
1216}
1217
1218#[derive(Debug, Clone, Copy)]
1224pub(crate) struct PropCommands {
1225 get: &'static str,
1227 list: &'static str,
1229 list_wildcard: bool,
1231}
1232
1233impl PropCommands {
1234 const FREE: Self = Self { get: "DbGetProperty", list: "DbGetPropertyList", list_wildcard: true };
1235 const CLASS: Self = Self { get: "DbGetClassProperty", list: "DbGetClassPropertyList", list_wildcard: false };
1236 pub(crate) const DEV: Self = Self { get: "DbGetDeviceProperty", list: "DbGetDevicePropertyList", list_wildcard: true };
1237}
1238
1239mod get_prop {
1241
1242 use super::{Error, ErrorKind, Named, Result, Scalar, Spectrum};
1243
1244 #[derive(Debug)]
1250 pub enum PropReply {
1251 Listing {
1254 listing: Spectrum<str>,
1258 names: Spectrum<str>,
1261 index: usize,
1263 cursor: usize,
1265 },
1266 Attr {
1274 listing: Spectrum<str>,
1276 begin: usize,
1278 count: usize,
1280 names: Option<Spectrum<str>>,
1283 index: usize,
1285 cursor: usize,
1287 },
1288 }
1289
1290 impl PropReply {
1291
1292 pub(super) fn empty() -> Self {
1295 Self::Listing { listing: Spectrum::new(), names: Spectrum::new(), index: 0, cursor: 0 }
1296 }
1297
1298 pub(super) fn new(obj_name: &str, listing: Spectrum<str>, names: Spectrum<str>) -> Result<Self> {
1302 let cursor = read_head(&listing, obj_name, names.len(), "property count")?;
1303 Ok(Self::Listing { listing, names, index: 0, cursor })
1304 }
1305
1306 pub fn len(&self) -> usize {
1309 match self {
1310 Self::Listing { names, index, .. } => names.len() - index,
1311 Self::Attr { names: Some(names), index, .. } => names.len() - index,
1312 Self::Attr { names: None, count, index, .. } => count - index,
1313 }
1314 }
1315
1316 pub fn is_empty(&self) -> bool {
1318 self.len() == 0
1319 }
1320
1321 pub fn next(&mut self) -> Option<Result<Named<Spectrum<str>>>> {
1332
1333 let (listing, names, index, cursor) = match self {
1334 Self::Listing { listing, names, index, cursor } => (listing, names, index, cursor),
1335 Self::Attr { listing, begin, count, names, index, cursor } => {
1336 return next_attr_prop(listing, *begin, *count, names.as_ref(), index, cursor);
1337 }
1338 };
1339
1340 let expected = names.get([*index])?;
1341 *index += 1;
1342
1343 match next_prop(listing, expected, cursor) {
1344 Ok(prop) => Some(Ok(prop)),
1345 Err(err) => {
1346 *index = names.len();
1347 Some(Err(err))
1348 }
1349 }
1350
1351 }
1352
1353 }
1354
1355 fn next_prop(listing: &Spectrum<str>, expected: &str, cursor: &mut usize) -> Result<Named<Spectrum<str>>> {
1361
1362 let (Some(name), Some(count_raw)) = (listing.get([*cursor]), listing.get([*cursor + 1])) else {
1363 return Err(Error::new(ErrorKind::InvalidData)
1364 .with_append_description("Missing property name and its count")
1365 .with_append_description(format_args!("{listing:?}")));
1366 };
1367
1368 if !name.eq_ignore_ascii_case(expected) {
1369 return Err(Error::new(ErrorKind::InvalidData)
1370 .with_append_description(format_args!("Incoherent property name ({name:?}) from what was requested ({expected:?})")));
1371 }
1372
1373 let Ok(count) = count_raw.parse::<usize>() else {
1374 return Err(Error::new(ErrorKind::InvalidData)
1375 .with_append_description(format_args!("Invalid property values count ({count_raw:?})")));
1376 };
1377
1378 let name_index = *cursor;
1379 let begin = *cursor + 2;
1380 *cursor = begin + count;
1381
1382 if *cursor > listing.len() {
1383 return Err(Error::new(ErrorKind::InvalidData)
1384 .with_append_description("Missing property values")
1385 .with_append_description(format_args!("{listing:?}")));
1386 }
1387
1388 let name = listing.slice(name_index..name_index + 1).into_scalar().expect("one name");
1389 Ok(Named::new(name, listing.slice(begin..*cursor)))
1390
1391 }
1392
1393 fn next_attr_prop(
1400 listing: &Spectrum<str>,
1401 begin: usize,
1402 count: usize,
1403 names: Option<&Spectrum<str>>,
1404 index: &mut usize,
1405 cursor: &mut usize,
1406 ) -> Option<Result<Named<Spectrum<str>>>> {
1407
1408 let Some(names) = names else {
1409 if *index >= count {
1410 return None;
1411 }
1412 *index += 1;
1413 return Some(next_value_prop(listing, cursor));
1414 };
1415
1416 let name = names.get_scalar([*index])?;
1417 *index += 1;
1418
1419 let mut lookup = begin;
1420 for _ in 0..count {
1421 match next_value_prop(listing, &mut lookup) {
1422 Ok(prop) if prop.name.value().eq_ignore_ascii_case(name.value()) => {
1423 return Some(Ok(prop));
1424 }
1425 Ok(_) => {}
1426 Err(err) => {
1427 *index = names.len();
1428 return Some(Err(err));
1429 }
1430 }
1431 }
1432
1433 Some(Ok(Named::new(name, Spectrum::new())))
1434
1435 }
1436
1437 fn next_value_prop(listing: &Spectrum<str>, cursor: &mut usize) -> Result<Named<Spectrum<str>>> {
1442
1443 let name = next_str(listing, cursor, "property name")?;
1444 let count = next_count(listing, cursor, "property values count")?;
1445
1446 let begin = *cursor;
1447 *cursor += count.max(1);
1448 if *cursor > listing.len() {
1449 return Err(Error::new(ErrorKind::InvalidData)
1450 .with_append_description("Missing property values")
1451 .with_append_description(format_args!("{listing:?}")));
1452 }
1453
1454 Ok(Named::new(name, listing.slice(begin..begin + count)))
1455
1456 }
1457
1458 #[derive(Debug)]
1465 pub struct AttrPropReply {
1466 listing: Spectrum<str>,
1468 attr_names: Spectrum<str>,
1471 prop_names: Option<Spectrum<str>>,
1473 index: usize,
1475 cursor: usize,
1477 }
1478
1479 impl AttrPropReply {
1480
1481 pub(super) fn empty() -> Self {
1484 Self { listing: Spectrum::new(), attr_names: Spectrum::new(), prop_names: None, index: 0, cursor: 0 }
1485 }
1486
1487 pub(super) fn new(
1491 obj_name: &str,
1492 listing: Spectrum<str>,
1493 attr_names: Spectrum<str>,
1494 prop_names: Option<Spectrum<str>>,
1495 ) -> Result<Self> {
1496 let cursor = read_head(&listing, obj_name, attr_names.len(), "attribute count")?;
1497 Ok(Self { listing, attr_names, prop_names, index: 0, cursor })
1498 }
1499
1500 pub fn len(&self) -> usize {
1502 self.attr_names.len() - self.index
1503 }
1504
1505 pub fn next(&mut self) -> Option<Result<Named<PropReply>>> {
1511
1512 let Self { listing, attr_names, prop_names, index, cursor } = self;
1513
1514 let expected = attr_names.get([*index])?;
1515 *index += 1;
1516
1517 let res = (|| {
1518
1519 let name = next_str(listing, cursor, "attribute name")?;
1520 if !name.value().eq_ignore_ascii_case(expected) {
1521 return Err(Error::new(ErrorKind::InvalidData)
1522 .with_append_description(format_args!("Incoherent attribute name ({:?}) from what was requested ({expected:?})",
1523 name.value())));
1524 }
1525
1526 let count = next_count(listing, cursor, "property count")?;
1529 let begin = *cursor;
1530 for _ in 0..count {
1531 next_value_prop(listing, cursor)?;
1532 }
1533
1534 Ok(Named::new(name, PropReply::Attr {
1535 listing: listing.clone(),
1536 begin,
1537 count,
1538 names: prop_names.clone(),
1539 index: 0,
1540 cursor: begin,
1541 }))
1542
1543 })();
1544
1545 if res.is_err() {
1546 *index = attr_names.len();
1547 }
1548
1549 Some(res)
1550
1551 }
1552
1553 }
1554
1555 fn read_head(listing: &Spectrum<str>, obj_name: &str, expected: usize, what: &str) -> Result<usize> {
1558
1559 let mut cursor = 0;
1560
1561 let output_obj_name = next_str(listing, &mut cursor, "object name")?;
1562 if !output_obj_name.value().eq_ignore_ascii_case(obj_name) {
1563 return Err(Error::new(ErrorKind::InvalidData)
1564 .with_append_description(format_args!("Incoherent name get ({:?}) from what was requested ({obj_name:?})",
1565 output_obj_name.value())));
1566 }
1567
1568 let count = next_count(listing, &mut cursor, what)?;
1569 if count != expected {
1570 return Err(Error::new(ErrorKind::InvalidData)
1571 .with_append_description(format_args!("Incoherent {what} ({count}) from what was requested ({expected})")));
1572 }
1573
1574 Ok(cursor)
1575
1576 }
1577
1578 fn next_str(listing: &Spectrum<str>, cursor: &mut usize, what: &str) -> Result<Scalar<str>> {
1580 let Some(value) = listing.get_scalar([*cursor]) else {
1581 return Err(Error::new(ErrorKind::InvalidData)
1582 .with_append_description(format_args!("Missing {what}"))
1583 .with_append_description(format_args!("{listing:?}")));
1584 };
1585 *cursor += 1;
1586 Ok(value)
1587 }
1588
1589 fn next_count(listing: &Spectrum<str>, cursor: &mut usize, what: &str) -> Result<usize> {
1591 let raw = next_str(listing, cursor, what)?;
1592 raw.value().trim().parse::<usize>().map_err(|_| Error::new(ErrorKind::InvalidData)
1593 .with_append_description(format_args!("Invalid {what}: {:?}", raw.value())))
1594 }
1595
1596}
1597
1598pub trait GetPropSpec<Names> {
1604
1605 type Output;
1607
1608 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output>;
1613
1614}
1615
1616impl<T> GetPropSpec<&'_ str> for T
1619where
1620 T: FromProp,
1621{
1622
1623 type Output = T;
1624
1625 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1626 match props.next() {
1627 Some(entry) => T::from_prop(&entry?.value),
1628 None => Err(unexpected_len_err(1)),
1629 }
1630 }
1631
1632}
1633
1634impl<T> GetPropSpec<&'_ [&'_ str]> for T
1635where
1636 T: FromProp,
1637{
1638
1639 type Output = Vec<Result<T>>;
1640
1641 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1642
1643 let mut values = Vec::with_capacity(props.len());
1646
1647 while let Some(entry) = props.next() {
1648 values.push(T::from_prop(&entry?.value));
1649 }
1650
1651 Ok(values)
1652
1653 }
1654
1655}
1656
1657impl<T> GetPropSpec<Spectrum<str>> for T
1658where
1659 T: FromProp,
1660{
1661
1662 type Output = Vec<Result<T>>;
1663
1664 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1665 <T as GetPropSpec<&[&str]>>::collect(props)
1666 }
1667
1668}
1669
1670impl<T> GetPropSpec<&Spectrum<str>> for T
1671where
1672 T: FromProp,
1673{
1674
1675 type Output = Vec<Result<T>>;
1676
1677 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1678 <T as GetPropSpec<&[&str]>>::collect(props)
1679 }
1680
1681}
1682
1683impl<T, const N: usize> GetPropSpec<[&'_ str; N]> for T
1684where
1685 T: FromProp,
1686{
1687
1688 type Output = [Result<T>; N];
1689
1690 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1691
1692 let mut slots = [const { None }; N];
1695 for slot in &mut slots {
1696 let entry = props.next().ok_or_else(|| unexpected_len_err(N))?;
1697 *slot = Some(T::from_prop(&entry?.value));
1698 }
1699 if props.next().is_some() {
1700 return Err(unexpected_len_err(N));
1701 }
1702
1703 Ok(slots.map(|slot| slot.expect("every slot is filled")))
1704
1705 }
1706
1707}
1708
1709impl GetPropSpec<All> for Spectrum<str> {
1710
1711 type Output = Vec<Named<Spectrum<str>>>;
1712
1713 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1714
1715 let mut values = Vec::with_capacity(props.len());
1718
1719 while let Some(entry) = props.next() {
1720 values.push(entry?);
1721 }
1722
1723 Ok(values)
1724
1725 }
1726
1727}
1728
1729macro_rules! impl_get_prop_spec_tuple {
1730 ( @one: $comp:ident ) => { 1 };
1731 ( @name: $comp:ident ) => { &'name str };
1732 ( $( $comp:ident )* ) => {
1733
1734 #[allow(non_snake_case)]
1735 impl<'name, $($comp,)* > GetPropSpec<( $( impl_get_prop_spec_tuple!(@name: $comp), )* )> for ( $($comp,)* )
1736 where
1737 $(
1738 $comp: FromProp,
1739 )*
1740 {
1741
1742 type Output = ( $( Result<$comp>,)* );
1743
1744 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1745
1746 const LEN: usize = 0 $( + impl_get_prop_spec_tuple!(@one: $comp) )*;
1747
1748 let output = ( $( {
1752 let entry = props.next().ok_or_else(|| unexpected_len_err(LEN))?;
1753 $comp::from_prop(&entry?.value)
1754 }, )* );
1755 if props.next().is_some() {
1756 return Err(unexpected_len_err(LEN));
1757 }
1758
1759 Ok(output)
1760
1761 }
1762
1763 }
1764
1765 };
1766}
1767
1768impl_get_prop_spec_tuple!(A);
1769impl_get_prop_spec_tuple!(A B);
1770impl_get_prop_spec_tuple!(A B C);
1771impl_get_prop_spec_tuple!(A B C D);
1772impl_get_prop_spec_tuple!(A B C D E);
1773impl_get_prop_spec_tuple!(A B C D E F);
1774
1775mod set_prop {
1781
1782 use super::{Cow, IntoProp, SetPropSpec};
1783
1784 pub struct Builder<'a> {
1785 array: Vec<Cow<'a, str>>,
1786 count: usize,
1787 }
1788
1789 impl<'a> Builder<'a> {
1790
1791 pub fn new() -> Self {
1792 Self {
1793 array: vec![Cow::Borrowed("")], count: 0,
1795 }
1796 }
1797
1798 pub fn push<T>(&mut self, name: &'a str, value: T)
1799 where
1800 T: IntoProp<'a>,
1801 {
1802 self.array.push(Cow::Borrowed(name));
1803 self.array.push(Cow::Borrowed("")); let len = self.array.len();
1805 self.array.extend(value.into_prop());
1806 let count = self.array.len() - len;
1807 self.array[len - 1] = Cow::Owned(format!("{count}")); self.count += 1;
1809 }
1810
1811 pub fn finalize(mut self) -> Vec<Cow<'a, str>> {
1812 self.array[0] = Cow::Owned(format!("{}", self.count));
1814 self.array
1815 }
1816
1817 }
1818
1819 pub struct AttrBuilder<'a> {
1822 array: Vec<Cow<'a, str>>,
1823 count: usize,
1824 }
1825
1826 impl<'a> AttrBuilder<'a> {
1827
1828 pub fn new() -> Self {
1829 Self {
1830 array: vec![Cow::Borrowed("")], count: 0,
1832 }
1833 }
1834
1835 pub fn push<S>(&mut self, attr_name: &'a str, spec: S)
1836 where
1837 S: SetPropSpec<'a>,
1838 {
1839 let mut builder = Builder::new();
1840 spec.push_to_builder(&mut builder);
1841 self.array.push(Cow::Borrowed(attr_name));
1842 self.array.extend(builder.finalize());
1843 self.count += 1;
1844 }
1845
1846 pub fn finalize(mut self) -> Vec<Cow<'a, str>> {
1847 self.array[0] = Cow::Owned(format!("{}", self.count));
1848 self.array
1849 }
1850
1851 }
1852
1853}
1854
1855pub trait SetPropSpec<'a>: Sized {
1861 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>);
1863}
1864
1865impl<'a, T> SetPropSpec<'a> for (&'a str, T)
1867where
1868 T: IntoProp<'a>,
1869{
1870
1871 #[inline]
1872 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1873 builder.push(self.0, self.1);
1874 }
1875
1876}
1877
1878impl<'a, T, const N: usize> SetPropSpec<'a> for [(&'a str, T); N]
1880where
1881 T: IntoProp<'a>,
1882{
1883
1884 #[inline]
1885 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1886 for (name, value) in self {
1887 builder.push(name, value);
1888 }
1889 }
1890
1891}
1892
1893impl<'a, 'aa: 'a, T> SetPropSpec<'a> for Vec<(&'aa str, T)>
1895where
1896 T: IntoProp<'a>,
1897{
1898
1899 #[inline]
1900 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1901 for (name, value) in self {
1902 builder.push(name, value);
1903 }
1904 }
1905
1906}
1907
1908macro_rules! impl_set_prop_spec_tuple {
1909 ( @name: $comp:ident ) => { &'a str };
1910 ( $( $comp:ident )* ) => {
1911
1912 #[allow(non_snake_case, unused_assignments)]
1913 impl<'a, $($comp,)*> SetPropSpec<'a> for ( $( (impl_set_prop_spec_tuple!(@name: $comp), $comp), )* )
1914 where
1915 $(
1916 $comp: IntoProp<'a>,
1917 )*
1918 {
1919
1920 #[inline]
1921 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1922 let ( $($comp,)* ) = self;
1923 $(
1924 builder.push($comp.0, $comp.1);
1925 )*
1926 }
1927
1928 }
1929
1930 };
1931}
1932
1933impl_set_prop_spec_tuple!(A);
1934impl_set_prop_spec_tuple!(A B);
1935impl_set_prop_spec_tuple!(A B C);
1936impl_set_prop_spec_tuple!(A B C D);
1937impl_set_prop_spec_tuple!(A B C D E);
1938impl_set_prop_spec_tuple!(A B C D E F);
1939
1940#[derive(Debug, Clone, Copy)]
1946pub(crate) struct AttrPropCommands {
1947 get: &'static str,
1949 list: &'static str,
1951}
1952
1953impl AttrPropCommands {
1954 pub(crate) const CLASS: Self = Self { get: "DbGetClassAttributeProperty2", list: "DbGetClassAttributeList" };
1955 pub(crate) const DEV: Self = Self { get: "DbGetDeviceAttributeProperty2", list: "DbGetDeviceAttributeList" };
1956}
1957
1958pub trait GetAttrPropSpec<AttrNames, Names> {
1967
1968 type Output;
1970
1971 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output>;
1974
1975}
1976
1977fn next_attr<T: GetPropSpec<Names>, Names>(attrs: &mut get_prop::AttrPropReply) -> Option<Result<NamedResult<T::Output>>> {
1980 Some(attrs.next()?.map(|attr| attr.map(|mut props| T::collect(&mut props))))
1981}
1982
1983impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ str, Names> for T {
1986
1987 type Output = T::Output;
1988
1989 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
1990 match next_attr::<T, Names>(attrs) {
1991 Some(attr) => attr?.value,
1992 None => Err(unexpected_len_err(1)),
1993 }
1994 }
1995
1996}
1997
1998fn collect_attr_list<T: GetPropSpec<Names>, Names>(attrs: &mut get_prop::AttrPropReply) -> Result<Vec<Result<T::Output>>> {
2000 let mut outputs = Vec::with_capacity(attrs.len());
2001 while let Some(attr) = next_attr::<T, Names>(attrs) {
2002 outputs.push(attr?.value);
2003 }
2004 Ok(outputs)
2005}
2006
2007impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ [&'_ str], Names> for T {
2008 type Output = Vec<Result<T::Output>>;
2009 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2010 collect_attr_list::<T, Names>(attrs)
2011 }
2012}
2013
2014impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<Spectrum<str>, Names> for T {
2015 type Output = Vec<Result<T::Output>>;
2016 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2017 collect_attr_list::<T, Names>(attrs)
2018 }
2019}
2020
2021impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ Spectrum<str>, Names> for T {
2022 type Output = Vec<Result<T::Output>>;
2023 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2024 collect_attr_list::<T, Names>(attrs)
2025 }
2026}
2027
2028impl<T: GetPropSpec<Names>, Names, const N: usize> GetAttrPropSpec<[&'_ str; N], Names> for T {
2029
2030 type Output = [Result<T::Output>; N];
2031
2032 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2033 let mut slots = [const { None }; N];
2036 for slot in &mut slots {
2037 *slot = Some(next_attr::<T, Names>(attrs).ok_or_else(|| unexpected_len_err(N))??.value);
2038 }
2039 if attrs.next().is_some() {
2040 return Err(unexpected_len_err(N));
2041 }
2042 Ok(slots.map(|slot| slot.expect("every slot is filled")))
2043 }
2044
2045}
2046
2047impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<All, Names> for T {
2049
2050 type Output = Vec<NamedResult<T::Output>>;
2051
2052 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2053 let mut outputs = Vec::with_capacity(attrs.len());
2054 while let Some(attr) = next_attr::<T, Names>(attrs) {
2055 outputs.push(attr?);
2056 }
2057 Ok(outputs)
2058 }
2059
2060}
2061
2062macro_rules! impl_get_attr_prop_spec_tuple {
2063 ( @one: $index:tt ) => { 1 };
2064 ( @name: $index:tt ) => { &'name str };
2065 ( @output: $index:tt ) => { Result<T::Output> };
2066 ( @next: $index:tt, $attrs:ident ) => { next_attr::<T, Names>($attrs).ok_or_else(|| unexpected_len_err(LEN))??.value };
2067 ( $( $index:tt )* ) => {
2068
2069 impl<'name, T: GetPropSpec<Names>, Names> GetAttrPropSpec<( $( impl_get_attr_prop_spec_tuple!(@name: $index), )* ), Names> for T {
2070
2071 type Output = ( $( impl_get_attr_prop_spec_tuple!(@output: $index), )* );
2072
2073 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2074 const LEN: usize = 0 $( + impl_get_attr_prop_spec_tuple!(@one: $index) )*;
2075 let output = ( $( impl_get_attr_prop_spec_tuple!(@next: $index, attrs), )* );
2078 if attrs.next().is_some() {
2079 return Err(unexpected_len_err(LEN));
2080 }
2081 Ok(output)
2082 }
2083
2084 }
2085
2086 };
2087}
2088
2089impl_get_attr_prop_spec_tuple!(0);
2090impl_get_attr_prop_spec_tuple!(0 1);
2091impl_get_attr_prop_spec_tuple!(0 1 2);
2092impl_get_attr_prop_spec_tuple!(0 1 2 3);
2093impl_get_attr_prop_spec_tuple!(0 1 2 3 4);
2094impl_get_attr_prop_spec_tuple!(0 1 2 3 4 5);
2095
2096pub trait SetAttrPropSpec<'a>: Sized {
2107 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>);
2109}
2110
2111impl<'a, S> SetAttrPropSpec<'a> for (&'a str, S)
2113where
2114 S: SetPropSpec<'a>,
2115{
2116
2117 #[inline]
2118 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2119 builder.push(self.0, self.1);
2120 }
2121
2122}
2123
2124impl<'a, S, const N: usize> SetAttrPropSpec<'a> for [(&'a str, S); N]
2126where
2127 S: SetPropSpec<'a>,
2128{
2129
2130 #[inline]
2131 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2132 for (attr_name, spec) in self {
2133 builder.push(attr_name, spec);
2134 }
2135 }
2136
2137}
2138
2139impl<'a, S> SetAttrPropSpec<'a> for Vec<(&'a str, S)>
2141where
2142 S: SetPropSpec<'a>,
2143{
2144
2145 #[inline]
2146 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2147 for (attr_name, spec) in self {
2148 builder.push(attr_name, spec);
2149 }
2150 }
2151
2152}
2153
2154fn attr_prop_params<'a, Spec: SetAttrPropSpec<'a>>(obj_name: &str, spec: Spec) -> Spectrum<str> {
2156 let mut builder = set_prop::AttrBuilder::new();
2157 spec.push_to_builder(&mut builder);
2158 prop_params(obj_name, builder.finalize().iter().map(|param| &**param))
2159}
2160
2161#[cfg(test)]
2188mod tests {
2189
2190 use futures::future::BoxFuture;
2191
2192 use super::*;
2193
2194 #[allow(dead_code)]
2197 fn attr_props_in_send_future(db: &DatabaseProxy) -> BoxFuture<'_, Result<()>> {
2198 Box::pin(async move {
2199 let _ = db.get_dev_attr_prop_async::<f64, _, _>("motor/dev/1", "Position", "max_value").await?;
2200 let _ = db.get_class_attr_prop_async::<(String, f64), _, _>("Motor", ["Position"], ("label", "max_value")).await?;
2201 let _ = db.get_dev_attr_prop_async::<Spectrum<str>, _, _>("motor/dev/1", All, All).await?;
2202 Ok(())
2203 })
2204 }
2205
2206 fn reply(names: &[&str], listing: &[&str]) -> get_prop::PropReply {
2211 get_prop::PropReply::new(listing[0], Spectrum::from(listing), Spectrum::from(names)).unwrap()
2212 }
2213
2214 fn attr_reply(attr_names: &[&str], prop_names: Option<&[&str]>, listing: &[&str]) -> get_prop::AttrPropReply {
2218 get_prop::AttrPropReply::new(listing[0], Spectrum::from(listing), Spectrum::from(attr_names), prop_names.map(Spectrum::from)).unwrap()
2219 }
2220
2221 #[test]
2225 fn listing_head() {
2226
2227 let names = || Spectrum::from(&["prop"][..]);
2228
2229 let err = get_prop::PropReply::new("obj", Spectrum::from(&["another", "1", "prop", "0"][..]), names()).unwrap_err();
2230 assert_eq!(err.kind(), ErrorKind::InvalidData);
2231 let err = get_prop::PropReply::new("obj", Spectrum::from(&["obj", "2", "prop", "0"][..]), names()).unwrap_err();
2232 assert_eq!(err.kind(), ErrorKind::InvalidData);
2233 let err = get_prop::AttrPropReply::new("obj", Spectrum::from(&["obj", "2", "prop", "0"][..]), names(), None).unwrap_err();
2234 assert_eq!(err.kind(), ErrorKind::InvalidData);
2235
2236 let mut props = get_prop::PropReply::empty();
2237 assert!(props.is_empty());
2238 assert!(props.next().is_none());
2239 let mut attrs = get_prop::AttrPropReply::empty();
2240 assert_eq!(attrs.len(), 0);
2241 assert!(attrs.next().is_none());
2242
2243 }
2244
2245 fn attr_props(props: &mut get_prop::PropReply) -> Vec<(String, Vec<String>)> {
2247 let mut taken = Vec::new();
2248 while let Some(prop) = props.next() {
2249 let prop = prop.unwrap();
2250 taken.push((prop.name.value().to_string(), prop.value.iter().map(str::to_string).collect()));
2251 }
2252 taken
2253 }
2254
2255 const ATTR_LISTING: &[&str] = &[
2256 "sys/tg_test/1", "3",
2257 "first", "2", "label", "1", "First", "rel_change", "2", "-1", "2",
2258 "empty", "1", "unit", "0", " ",
2259 "none", "0",
2260 ];
2261
2262 #[test]
2267 fn attr_props_in_order() {
2268
2269 let mut reply = attr_reply(&["first", "empty", "none"], None, ATTR_LISTING);
2270 assert_eq!(reply.len(), 3);
2271
2272 let Named { name, value: mut props } = reply.next().unwrap().unwrap();
2273 assert_eq!(name.value(), "first");
2274 assert_eq!(props.len(), 2);
2275 assert_eq!(attr_props(&mut props), [
2276 ("label".to_string(), vec!["First".to_string()]),
2277 ("rel_change".to_string(), vec!["-1".to_string(), "2".to_string()]),
2278 ]);
2279
2280 let mut props = reply.next().unwrap().unwrap().value;
2281 assert_eq!(attr_props(&mut props), [("unit".to_string(), vec![])]);
2282
2283 let mut props = reply.next().unwrap().unwrap().value;
2284 assert!(attr_props(&mut props).is_empty());
2285
2286 assert!(reply.next().is_none());
2287
2288 }
2289
2290 #[test]
2293 fn attr_prop_lookup() {
2294
2295 let mut reply = attr_reply(&["first", "empty", "none"], Some(&["REL_CHANGE", "unit"]), ATTR_LISTING);
2296
2297 let mut props = reply.next().unwrap().unwrap().value;
2298 assert_eq!(props.len(), 2);
2299 assert_eq!(attr_props(&mut props), [
2300 ("rel_change".to_string(), vec!["-1".to_string(), "2".to_string()]),
2301 ("unit".to_string(), vec![]),
2302 ]);
2303
2304 let mut props = reply.next().unwrap().unwrap().value;
2305 assert_eq!(attr_props(&mut props), [
2306 ("REL_CHANGE".to_string(), vec![]),
2307 ("unit".to_string(), vec![]),
2308 ]);
2309
2310 }
2311
2312 #[test]
2316 fn incoherent_attr_props() {
2317
2318 let mut reply = attr_reply(&["asked", "behind"], None, &["obj", "2", "another", "0", "behind", "0"]);
2319 assert_eq!(reply.next().unwrap().unwrap_err().kind(), ErrorKind::InvalidData);
2320 assert!(reply.next().is_none());
2321
2322 let mut reply = attr_reply(&["asked"], None, &["obj", "1", "asked", "1", "label", "2", "one"]);
2323 assert_eq!(reply.next().unwrap().unwrap_err().kind(), ErrorKind::InvalidData);
2324
2325 }
2326
2327 #[test]
2331 fn attr_prop_write() {
2332 let params = attr_prop_params("obj", [
2333 ("first", vec![("label", "First"), ("unit", "mm")]),
2334 ("second", vec![("label", "Second")]),
2335 ]);
2336 assert_eq!(params.iter().collect::<Vec<_>>(), [
2337 "obj", "2",
2338 "first", "2", "label", "1", "First", "unit", "1", "mm",
2339 "second", "1", "label", "1", "Second",
2340 ]);
2341 }
2342
2343 #[test]
2346 fn props_in_order() {
2347
2348 let mut props = reply(&["first", "second"],
2349 &["sys/tg_test/1", "2", "first", "1", "one", "second", "2", "two", "three"]);
2350
2351 assert_eq!(props.len(), 2);
2352
2353 let Named { name, value: values } = props.next().unwrap().unwrap();
2354 assert_eq!(name.value(), "first");
2355 assert_eq!(values.iter().collect::<Vec<_>>(), ["one"]);
2356
2357 let Named { name, value: values } = props.next().unwrap().unwrap();
2358 assert_eq!(name.value(), "second");
2359 assert_eq!(values.iter().collect::<Vec<_>>(), ["two", "three"]);
2360
2361 assert!(props.next().is_none());
2362
2363 }
2364
2365 #[test]
2368 fn prop_without_value() {
2369 let mut props = reply(&["empty"], &["obj", "1", "empty", "0"]);
2370 let Named { name, value: values } = props.next().unwrap().unwrap();
2371 assert_eq!(name.value(), "empty");
2372 assert!(values.is_empty());
2373 }
2374
2375 #[test]
2378 fn incoherent_prop_name() {
2379 let mut props = reply(&["asked"], &["obj", "1", "another", "1", "one"]);
2380 let err = props.next().unwrap().unwrap_err();
2381 assert_eq!(err.kind(), ErrorKind::InvalidData);
2382 }
2383
2384 #[test]
2389 fn missing_prop_values() {
2390 let mut props = reply(&["prop", "behind"], &["obj", "2", "prop", "2", "one"]);
2391 let err = props.next().unwrap().unwrap_err();
2392 assert_eq!(err.kind(), ErrorKind::InvalidData);
2393 assert!(props.next().is_none());
2394 }
2395
2396 #[test]
2399 fn single_prop_parsed() {
2400 let mut props = reply(&["prop"], &["obj", "1", "prop", "1", "3.5"]);
2401 let value = <f64 as GetPropSpec<&str>>::collect(&mut props).unwrap();
2402 assert_eq!(value, 3.5);
2403 }
2404
2405}