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, Clone, 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")]
80 pub async fn database_info_async(&self) -> Result<Spectrum<str>> {
81 self.command_async("DbInfo", ()).await
82 }
83
84 #[doc(alias = "DbInfo")]
86 pub fn database_info(&self) -> Result<Spectrum<str>> {
87 self.block_on(self.database_info_async())?
88 }
89
90 #[doc(alias = "DbAddDevice")]
94 pub async fn add_dev_async(&self, name: &str, class: &str, server: &str) -> Result<()> {
95 self.command_async("DbAddDevice", [server, name, class]).await
96 }
97
98 #[doc(alias = "DbAddDevice")]
100 pub fn add_dev(&self, name: &str, class: &str, server: &str) -> Result<()> {
101 self.block_on(self.add_dev_async(name, class, server))?
102 }
103
104 #[doc(alias = "DbDeleteDevice")]
106 pub async fn delete_dev_async(&self, name: &str) -> Result<()> {
107 self.command_async("DbDeleteDevice", name).await
108 }
109
110 #[doc(alias = "DbDeleteDevice")]
112 pub fn delete_dev(&self, name: &str) -> Result<()> {
113 self.block_on(self.delete_dev_async(name))?
114 }
115
116 #[doc(alias = "DbAddServer")]
121 pub async fn add_server_async(&self, server: &str, devs: &[(&str, &str)]) -> Result<()> {
122 let mut args = Vec::with_capacity(1 + devs.len() * 2);
123 args.push(server);
124 args.extend(devs.iter().flat_map(|&(name, class)| [name, class]));
125 self.command_async("DbAddServer", &args[..]).await
126 }
127
128 #[doc(alias = "DbAddServer")]
130 pub fn add_server(&self, server: &str, devs: &[(&str, &str)]) -> Result<()> {
131 self.block_on(self.add_server_async(server, devs))?
132 }
133
134 #[doc(alias = "DbDeleteServer")]
136 pub async fn delete_server_async(&self, server: &str) -> Result<()> {
137 self.command_async("DbDeleteServer", server).await
138 }
139
140 #[doc(alias = "DbDeleteServer")]
142 pub fn delete_server(&self, server: &str) -> Result<()> {
143 self.block_on(self.delete_server_async(server))?
144 }
145
146 #[doc(alias = "DbRenameServer")]
148 pub async fn rename_server_async(&self, name: &str, new_name: &str) -> Result<()> {
149 self.command_async("DbRenameServer", [name, new_name]).await
150 }
151
152 #[doc(alias = "DbRenameServer")]
154 pub fn rename_server(&self, name: &str, new_name: &str) -> Result<()> {
155 self.block_on(self.rename_server_async(name, new_name))?
156 }
157
158 #[doc(alias = "DbGetDeviceClassList")]
162 pub async fn list_server_dev_async(&self, server: &str) -> Result<Vec<Named<Scalar<str>>>> {
163
164 let flat: Spectrum<str> = self.command_async("DbGetDeviceClassList", server).await?;
165
166 let mut pairs = Vec::with_capacity(flat.len() / 2);
167 let mut index = 0;
168
169 while let Some(dev_name) = flat.get_scalar([index]) {
170 let Some(class_name) = flat.get_scalar([index + 1]) else {
171 return Err(Error::new(ErrorKind::InvalidData)
172 .with_description(format!("Database answered device {:?} of server {server:?} without its class", dev_name.value()))
173 .with_append_description("Expected: a string spectrum of device/class pairs"));
174 };
175 pairs.push(Named::new(dev_name, class_name));
176 index += 2;
177 }
178
179 Ok(pairs)
180
181 }
182
183 #[doc(alias = "DbGetDeviceClassList")]
185 pub fn list_server_dev(&self, server: &str) -> Result<Vec<Named<Scalar<str>>>> {
186 self.block_on(self.list_server_dev_async(server))?
187 }
188
189 #[doc(alias = "DbGetDeviceWideList")]
194 pub async fn list_dev_async(&self, filter: &str) -> Result<Spectrum<str>> {
195 self.command_async("DbGetDeviceWideList", filter).await
196 }
197
198 #[doc(alias = "DbGetDeviceWideList")]
200 pub fn list_dev(&self, filter: &str) -> Result<Spectrum<str>> {
201 self.block_on(self.list_dev_async(filter))?
202 }
203
204 #[doc(alias = "DbGetDeviceMemberList")]
207 pub async fn list_dev_member_async(&self, filter: &str) -> Result<Spectrum<str>> {
208 self.command_async("DbGetDeviceMemberList", filter).await
209 }
210
211 #[doc(alias = "DbGetDeviceMemberList")]
213 pub fn list_dev_member(&self, filter: &str) -> Result<Spectrum<str>> {
214 self.block_on(self.list_dev_member_async(filter))?
215 }
216
217 #[doc(alias = "DbGetDeviceFamilyList")]
220 pub async fn list_dev_family_async(&self, filter: &str) -> Result<Spectrum<str>> {
221 self.command_async("DbGetDeviceFamilyList", filter).await
222 }
223
224 #[doc(alias = "DbGetDeviceFamilyList")]
226 pub fn list_dev_family(&self, filter: &str) -> Result<Spectrum<str>> {
227 self.block_on(self.list_dev_family_async(filter))?
228 }
229
230 #[doc(alias = "DbGetDeviceDomainList")]
233 pub async fn list_dev_domain_async(&self, filter: &str) -> Result<Spectrum<str>> {
234 self.command_async("DbGetDeviceDomainList", filter).await
235 }
236
237 #[doc(alias = "DbGetDeviceDomainList")]
239 pub fn list_dev_domain(&self, filter: &str) -> Result<Spectrum<str>> {
240 self.block_on(self.list_dev_domain_async(filter))?
241 }
242
243 #[doc(alias = "DbExportDevice")]
247 pub async fn export_dev_async(&self, info: ExportDevInfo<'_>) -> Result<()> {
248 self.command_async("DbExportDevice", data_from_export_dev_info(&[info][..])).await
249 }
250
251 #[doc(alias = "DbExportDevice")]
253 pub fn export_dev(&self, info: ExportDevInfo<'_>) -> Result<()> {
254 self.block_on(self.export_dev_async(info))?
255 }
256
257 #[doc(alias = "DbUnExportDevice")]
259 pub async fn unexport_dev_async(&self, dev_name: &str) -> Result<()> {
260 self.command_async("DbUnExportDevice", dev_name).await
261 }
262
263 #[doc(alias = "DbUnExportDevice")]
265 pub fn unexport_dev(&self, dev_name: &str) -> Result<()> {
266 self.block_on(self.unexport_dev_async(dev_name))?
267 }
268
269 #[doc(alias = "DbExportServer")]
271 pub async fn export_server_async(&self, infos: &[ExportDevInfo<'_>]) -> Result<()> {
272 self.command_async("DbExportServer", data_from_export_dev_info(infos)).await
273 }
274
275 #[doc(alias = "DbExportServer")]
277 pub fn export_server(&self, infos: &[ExportDevInfo<'_>]) -> Result<()> {
278 self.block_on(self.export_server_async(infos))?
279 }
280
281 #[doc(alias = "DbUnExportServer")]
283 pub async fn unexport_server_async(&self, server: &str) -> Result<()> {
284 self.command_async("DbUnExportServer", server).await
285 }
286
287 #[doc(alias = "DbUnExportServer")]
289 pub fn unexport_server(&self, server: &str) -> Result<()> {
290 self.block_on(self.unexport_server_async(server))?
291 }
292
293 #[doc(alias = "DbGetDeviceExportedList")]
296 pub async fn list_exported_dev_async(&self, filter: &str) -> Result<Spectrum<str>> {
297 self.command_async("DbGetDeviceExportedList", filter).await
298 }
299
300 #[doc(alias = "DbGetDeviceExportedList")]
302 pub fn list_exported_dev(&self, filter: &str) -> Result<Spectrum<str>> {
303 self.block_on(self.list_exported_dev_async(filter))?
304 }
305
306 #[doc(alias = "DbImportDevice")]
310 pub async fn import_dev_async(&self, dev_name: &str) -> Result<ImportDevInfo> {
311
312 let (
313 [exported, pid],
314 svalue,
315 ) = match self.command_async("DbImportDevice", dev_name).await.and_then(long2_string) {
316 Ok(ret) => ret,
317 Err(err) => {
318 if let ErrorKind::Reason(reason::DB_DeviceNotDefined) = err.kind() {
319 return Err(Error::new(ErrorKind::DevNotFound)
320 .with_description(format!("Device {dev_name:?} is not defined in the database"))
321 .with_parent(err));
322 } else {
323 return Err(err);
324 }
325 }
326 };
327
328 if svalue.len() != 5 && svalue.len() != 6 {
329 return Err(Error::new(ErrorKind::InvalidData)
330 .with_description(format!("Database answered {} strings for device {dev_name:?} where 5 or 6 were expected", svalue.len()))
331 .with_append_description(format_args!("Got: {svalue:?}")));
332 }
333
334 let field = |index| svalue.get_scalar([index]).unwrap();
336
337 Ok(ImportDevInfo {
338 name: field(0),
339 itr: field(1),
340 host: field(4),
341 version: field(2),
342 server: field(3),
343 class: svalue.get_scalar([5]),
344 exported: exported == 1,
345 pid,
346 })
347
348 }
349
350 #[doc(alias = "DbImportDevice")]
352 pub fn import_dev(&self, dev_name: &str) -> Result<ImportDevInfo> {
353 self.block_on(self.import_dev_async(dev_name))?
354 }
355
356 #[doc(alias = "DbGetDeviceInfo")]
361 pub async fn get_dev_info_async(&self, dev_name: &str) -> Result<DbDevInfo> {
362
363 let (
364 [exported, pid],
365 svalue,
366 ) = match self.command_async("DbGetDeviceInfo", dev_name).await.and_then(long2_string) {
367 Ok(ret) => ret,
368 Err(err) => {
369 if let ErrorKind::Reason(reason::DB_DeviceNotDefined) = err.kind() {
370 return Err(Error::new(ErrorKind::DevNotFound)
371 .with_description(format!("Device {dev_name:?} is not defined in the database"))
372 .with_parent(err));
373 } else {
374 return Err(err);
375 }
376 }
377 };
378
379 if svalue.len() != 7 && svalue.len() != 8 {
380 return Err(Error::new(ErrorKind::InvalidData)
381 .with_description(format!("Database answered {} strings for device {dev_name:?} where 7 or 8 were expected", svalue.len()))
382 .with_append_description(format_args!("Got: {svalue:?}")));
383 }
384
385 let field = |index| svalue.get_scalar([index]).unwrap();
387
388 Ok(DbDevInfo {
389 name: field(0),
390 itr: field(1),
391 host: Some(field(4)).filter(|host| host.value() != "nada"),
392 version: field(2),
393 server: field(3),
394 class: svalue.get_scalar([7]),
395 last_exported: Some(field(5)).filter(|time| time.value() != "?"),
396 last_unexported: Some(field(6)).filter(|time| time.value() != "?"),
397 exported: exported == 1,
398 pid: Some(pid).filter(|&pid| pid != 0),
399 })
400
401 }
402
403 #[doc(alias = "DbGetDeviceInfo")]
405 pub fn get_dev_info(&self, dev_name: &str) -> Result<DbDevInfo> {
406 self.block_on(self.get_dev_info_async(dev_name))?
407 }
408
409 #[doc(alias = "DbGetDeviceAlias")]
413 pub async fn get_dev_alias_async(&self, dev_name: &str) -> Result<Option<Scalar<str>>> {
414 match self.command_async::<_, Scalar<str>>("DbGetDeviceAlias", dev_name).await {
415 Ok(ret) => Ok(Some(ret)),
416 Err(err) => {
417 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
418 Ok(None)
419 } else {
420 Err(err)
421 }
422 }
423 }
424 }
425
426 #[doc(alias = "DbGetDeviceAlias")]
428 pub fn get_dev_alias(&self, dev_name: &str) -> Result<Option<Scalar<str>>> {
429 self.block_on(self.get_dev_alias_async(dev_name))?
430 }
431
432 #[doc(alias = "DbGetAliasDevice")]
434 pub async fn resolve_dev_alias_async(&self, alias: &str) -> Result<Scalar<str>> {
435 match self.command_async("DbGetAliasDevice", alias).await {
436 Ok(ret) => Ok(ret),
437 Err(err) => {
438 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
439 Err(Error::new(ErrorKind::AliasNotFound)
440 .with_description(format!("Device alias {alias:?} is not defined in the database"))
441 .with_parent(err))
442 } else {
443 Err(err)
444 }
445 }
446 }
447 }
448
449 #[doc(alias = "DbGetAliasDevice")]
451 pub fn resolve_dev_alias(&self, alias: &str) -> Result<Scalar<str>> {
452 self.block_on(self.resolve_dev_alias_async(alias))?
453 }
454
455 #[doc(alias = "DbGetDeviceAliasList")]
457 pub async fn list_dev_aliases_async(&self, filter: &str) -> Result<Spectrum<str>> {
458 self.command_async("DbGetDeviceAliasList", filter).await
459 }
460
461 #[doc(alias = "DbGetDeviceAliasList")]
463 pub fn list_dev_aliases(&self, filter: &str) -> Result<Spectrum<str>> {
464 self.block_on(self.list_dev_aliases_async(filter))?
465 }
466
467 #[doc(alias = "DbGetAttributeAlias")]
471 pub async fn get_attr_alias_async(&self, attr_name: &str) -> Result<Option<Scalar<str>>> {
472 match self.command_async::<_, Scalar<str>>("DbGetAttributeAlias", attr_name).await {
473 Ok(ret) => Ok(Some(ret)),
474 Err(err) => {
475 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
476 Ok(None)
477 } else {
478 Err(err)
479 }
480 }
481 }
482 }
483
484 #[doc(alias = "DbGetAttributeAlias")]
486 pub fn get_attr_alias(&self, attr_name: &str) -> Result<Option<Scalar<str>>> {
487 self.block_on(self.get_attr_alias_async(attr_name))?
488 }
489
490 #[doc(alias = "DbGetAliasAttribute")]
492 pub async fn resolve_attr_alias_async(&self, alias: &str) -> Result<Scalar<str>> {
493 match self.command_async("DbGetAliasAttribute", alias).await {
494 Ok(ret) => Ok(ret),
495 Err(err) => {
496 if let ErrorKind::Reason(reason::DB_AliasNotDefined) = err.kind() {
497 Err(Error::new(ErrorKind::AliasNotFound)
498 .with_description(format!("Attribute alias {alias:?} is not defined in the database"))
499 .with_parent(err))
500 } else {
501 Err(err)
502 }
503 }
504 }
505 }
506
507 #[doc(alias = "DbGetAliasAttribute")]
509 pub fn resolve_attr_alias(&self, alias: &str) -> Result<Scalar<str>> {
510 self.block_on(self.resolve_attr_alias_async(alias))?
511 }
512
513 #[doc(alias = "DbGetAttributeAliasList")]
515 pub async fn list_attr_aliases_async(&self, filter: &str) -> Result<Spectrum<str>> {
516 self.command_async("DbGetAttributeAliasList", filter).await
517 }
518
519 #[doc(alias = "DbGetAttributeAliasList")]
521 pub fn list_attr_aliases(&self, filter: &str) -> Result<Spectrum<str>> {
522 self.block_on(self.list_attr_aliases_async(filter))?
523 }
524
525 #[doc(alias = "DbGetPropertyList")]
529 pub async fn list_free_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
530 self.command_async("DbGetPropertyList", [obj_name, filter]).await
531 }
532
533 #[doc(alias = "DbGetPropertyList")]
535 pub fn list_free_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
536 self.block_on(self.list_free_prop_async(obj_name, filter))?
537 }
538
539 #[doc(alias = "DbGetClassPropertyList")]
543 #[doc(alias = "DbGetClassPropertyListWildcard")]
544 pub async fn list_class_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
545 if filter == "*" {
546 self.command_async("DbGetClassPropertyList", [obj_name]).await
547 } else {
548 self.command_async("DbGetClassPropertyListWildcard", [obj_name, filter]).await
549 }
550 }
551
552 #[doc(alias = "DbGetClassPropertyList")]
554 #[doc(alias = "DbGetClassPropertyListWildcard")]
555 pub fn list_class_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
556 self.block_on(self.list_class_prop_async(obj_name, filter))?
557 }
558
559 #[doc(alias = "DbGetDevicePropertyList")]
563 pub async fn list_dev_prop_async(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
564 self.command_async("DbGetDevicePropertyList", [obj_name, filter]).await
565 }
566
567 #[doc(alias = "DbGetDevicePropertyList")]
569 pub fn list_dev_prop(&self, obj_name: &str, filter: &str) -> Result<Spectrum<str>> {
570 self.block_on(self.list_dev_prop_async(obj_name, filter))?
571 }
572
573 pub(crate) async fn get_raw_prop_async(&self,
582 commands: PropCommands,
583 obj_name: &str,
584 params: Option<Spectrum<str>>,
585 ) -> Result<get_prop::PropReply> {
586
587 let params = match params {
588 Some(params) => params,
589 None => {
590 let list_params = [obj_name, "*"];
591 let list_params = if commands.list_wildcard { &list_params[..] } else { &list_params[0..1] };
592 let names: Spectrum<str> = self.command_async(commands.list, list_params).await?;
593 prop_params(obj_name, names.iter())
594 }
595 };
596
597 let names = params.slice(1..);
598
599 if names.is_empty() {
604 return Ok(get_prop::PropReply::empty());
605 }
606
607 let listing: Spectrum<str> = self.command_async(commands.get, params).await?;
608 get_prop::PropReply::new(obj_name, listing, names)
609
610 }
611
612 fn get_any_prop_async<Spec, Names: ToNames>(&self,
614 commands: PropCommands,
615 obj_name: &str,
616 names: Names,
617 ) -> impl Future<Output = Result<Spec::Output>> + Send
618 where
619 Spec: GetPropSpec<Names>,
620 {
621 let params = names.iter_names().map(|names| prop_params(obj_name, names));
622 async move {
623 let mut reply = self.get_raw_prop_async(commands, obj_name, params).await?;
624 Spec::collect(&mut reply)
625 }
626 }
627
628 #[doc(alias = "DbGetProperty")]
633 pub fn get_free_prop_async<Spec, Names: ToNames>(&self, obj_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
634 where
635 Spec: GetPropSpec<Names>,
636 {
637 self.get_any_prop_async::<Spec, Names>(PropCommands::FREE, obj_name, names)
638 }
639
640 #[doc(alias = "DbGetProperty")]
642 pub fn get_free_prop<Spec, Names: ToNames>(&self, obj_name: &str, names: Names) -> Result<Spec::Output>
643 where
644 Spec: GetPropSpec<Names>,
645 {
646 self.block_on(self.get_free_prop_async::<Spec, Names>(obj_name, names))?
647 }
648
649 #[doc(alias = "DbGetClassProperty")]
654 pub fn get_class_prop_async<Spec, Names: ToNames>(&self, class_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
655 where
656 Spec: GetPropSpec<Names>,
657 {
658 self.get_any_prop_async::<Spec, Names>(PropCommands::CLASS, class_name, names)
659 }
660
661 #[doc(alias = "DbGetClassProperty")]
663 pub fn get_class_prop<Spec, Names: ToNames>(&self, class_name: &str, names: Names) -> Result<Spec::Output>
664 where
665 Spec: GetPropSpec<Names>,
666 {
667 self.block_on(self.get_class_prop_async::<Spec, Names>(class_name, names))?
668 }
669
670 #[doc(alias = "DbGetDeviceProperty")]
694 pub fn get_dev_prop_async<Spec, Names: ToNames>(&self, dev_name: &str, names: Names) -> impl Future<Output = Result<Spec::Output>> + Send
695 where
696 Spec: GetPropSpec<Names>,
697 {
698 self.get_any_prop_async::<Spec, Names>(PropCommands::DEV, dev_name, names)
699 }
700
701 #[doc(alias = "DbGetDeviceProperty")]
703 pub fn get_dev_prop<Spec, Names: ToNames>(&self, dev_name: &str, names: Names) -> Result<Spec::Output>
704 where
705 Spec: GetPropSpec<Names>,
706 {
707 self.block_on(self.get_dev_prop_async::<Spec, Names>(dev_name, names))?
708 }
709
710 pub(crate) async fn prop_command_async(&self, cmd_name: &'static str, params: Spectrum<str>) -> Result<()> {
715 self.command_async(cmd_name, params).await
716 }
717
718 #[doc(alias = "DbPutProperty")]
723 pub fn set_free_prop_async<'a, Spec>(&self, obj_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
724 where
725 Spec: SetPropSpec<'a>,
726 {
727 self.prop_command_async("DbPutProperty", prop_params(obj_name, set_prop_params(spec).iter().map(|param| &**param)))
728 }
729
730 #[doc(alias = "DbPutProperty")]
732 pub fn set_free_prop<'a, Spec>(&self, obj_name: &'a str, spec: Spec) -> Result<()>
733 where
734 Spec: SetPropSpec<'a>,
735 {
736 self.block_on(self.set_free_prop_async(obj_name, spec))?
737 }
738
739 #[doc(alias = "DbPutClassProperty")]
744 pub fn set_class_prop_async<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
745 where
746 Spec: SetPropSpec<'a>,
747 {
748 self.prop_command_async("DbPutClassProperty", prop_params(class_name, set_prop_params(spec).iter().map(|param| &**param)))
749 }
750
751 #[doc(alias = "DbPutClassProperty")]
753 pub fn set_class_prop<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> Result<()>
754 where
755 Spec: SetPropSpec<'a>,
756 {
757 self.block_on(self.set_class_prop_async(class_name, spec))?
758 }
759
760 #[doc(alias = "DbPutDeviceProperty")]
778 pub fn set_dev_prop_async<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
779 where
780 Spec: SetPropSpec<'a>,
781 {
782 self.prop_command_async("DbPutDeviceProperty", prop_params(dev_name, set_prop_params(spec).iter().map(|param| &**param)))
783 }
784
785 #[doc(alias = "DbPutDeviceProperty")]
787 pub fn set_dev_prop<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> Result<()>
788 where
789 Spec: SetPropSpec<'a>,
790 {
791 self.block_on(self.set_dev_prop_async(dev_name, spec))?
792 }
793
794 #[doc(alias = "DbDeleteProperty")]
799 pub fn delete_free_prop_async<Names: ToNamesNotAll>(&self, obj_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
800 self.prop_command_async("DbDeleteProperty", prop_params(obj_name, names.iter_names_not_all()))
801 }
802
803 #[doc(alias = "DbDeleteProperty")]
805 pub fn delete_free_prop<Names: ToNamesNotAll>(&self, obj_name: &str, names: Names) -> Result<()> {
806 self.block_on(self.delete_free_prop_async(obj_name, names))?
807 }
808
809 #[doc(alias = "DbDeleteClassProperty")]
814 pub fn delete_class_prop_async<Names: ToNamesNotAll>(&self, class_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
815 self.prop_command_async("DbDeleteClassProperty", prop_params(class_name, names.iter_names_not_all()))
816 }
817
818 #[doc(alias = "DbDeleteClassProperty")]
820 pub fn delete_class_prop<Names: ToNamesNotAll>(&self, class_name: &str, names: Names) -> Result<()> {
821 self.block_on(self.delete_class_prop_async(class_name, names))?
822 }
823
824 #[doc(alias = "DbDeleteDeviceProperty")]
837 pub fn delete_dev_prop_async<Names: ToNamesNotAll>(&self, dev_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
838 self.prop_command_async("DbDeleteDeviceProperty", prop_params(dev_name, names.iter_names_not_all()))
839 }
840
841 #[doc(alias = "DbDeleteDeviceProperty")]
843 pub fn delete_dev_prop<Names: ToNamesNotAll>(&self, dev_name: &str, names: Names) -> Result<()> {
844 self.block_on(self.delete_dev_prop_async(dev_name, names))?
845 }
846
847 pub(crate) async fn get_raw_attr_prop_async(&self,
860 commands: AttrPropCommands,
861 obj_name: &str,
862 params: Option<Spectrum<str>>,
863 prop_names: Option<Spectrum<str>>,
864 ) -> Result<get_prop::AttrPropReply> {
865
866 let params = match params {
867 Some(params) => params,
868 None => {
869 let attr_names: Spectrum<str> = self.command_async(commands.list, [obj_name, "*"]).await?;
870 prop_params(obj_name, attr_names.iter())
871 }
872 };
873
874 let attr_names = params.slice(1..);
876
877 if attr_names.is_empty() {
880 return Ok(get_prop::AttrPropReply::empty());
881 }
882
883 let listing: Spectrum<str> = self.command_async(commands.get, params).await?;
884 get_prop::AttrPropReply::new(obj_name, listing, attr_names, prop_names)
885
886 }
887
888 fn get_any_attr_prop_async<Spec, AttrNames, Names>(&self,
891 commands: AttrPropCommands,
892 obj_name: &str,
893 attr_names: AttrNames,
894 prop_names: Names,
895 ) -> impl Future<Output = Result<Spec::Output>> + Send
896 where
897 Spec: GetAttrPropSpec<AttrNames, Names>,
898 AttrNames: ToNames,
899 Names: ToNames,
900 {
901 let params = attr_names.iter_names().map(|attr_names| prop_params(obj_name, attr_names));
902 let prop_names = prop_names.to_names();
903 async move {
904 let mut reply = self.get_raw_attr_prop_async(commands, obj_name, params, prop_names).await?;
905 Spec::collect(&mut reply)
906 }
907 }
908
909 #[doc(alias = "DbGetClassAttributeProperty2")]
915 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
916 where
917 Spec: GetAttrPropSpec<AttrNames, Names>,
918 AttrNames: ToNames,
919 Names: ToNames,
920 {
921 self.get_any_attr_prop_async::<Spec, AttrNames, Names>(AttrPropCommands::CLASS, class_name, attr_names, prop_names)
922 }
923
924 #[doc(alias = "DbGetClassAttributeProperty2")]
927 pub fn get_class_attr_prop<Spec, AttrNames, Names>(&self, class_name: &str, attr_names: AttrNames, prop_names: Names) -> Result<Spec::Output>
928 where
929 Spec: GetAttrPropSpec<AttrNames, Names>,
930 AttrNames: ToNames,
931 Names: ToNames,
932 {
933 self.block_on(self.get_class_attr_prop_async::<Spec, AttrNames, Names>(class_name, attr_names, prop_names))?
934 }
935
936 #[doc(alias = "DbGetDeviceAttributeProperty2")]
961 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
962 where
963 Spec: GetAttrPropSpec<AttrNames, Names>,
964 AttrNames: ToNames,
965 Names: ToNames,
966 {
967 self.get_any_attr_prop_async::<Spec, AttrNames, Names>(AttrPropCommands::DEV, dev_name, attr_names, prop_names)
968 }
969
970 #[doc(alias = "DbGetDeviceAttributeProperty2")]
973 pub fn get_dev_attr_prop<Spec, AttrNames, Names>(&self, dev_name: &str, attr_names: AttrNames, prop_names: Names) -> Result<Spec::Output>
974 where
975 Spec: GetAttrPropSpec<AttrNames, Names>,
976 AttrNames: ToNames,
977 Names: ToNames,
978 {
979 self.block_on(self.get_dev_attr_prop_async::<Spec, AttrNames, Names>(dev_name, attr_names, prop_names))?
980 }
981
982 #[doc(alias = "DbPutClassAttributeProperty2")]
987 pub fn set_class_attr_prop_async<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
988 where
989 Spec: SetAttrPropSpec<'a>,
990 {
991 self.prop_command_async("DbPutClassAttributeProperty2", attr_prop_params(class_name, spec))
992 }
993
994 #[doc(alias = "DbPutClassAttributeProperty2")]
997 pub fn set_class_attr_prop<'a, Spec>(&self, class_name: &'a str, spec: Spec) -> Result<()>
998 where
999 Spec: SetAttrPropSpec<'a>,
1000 {
1001 self.block_on(self.set_class_attr_prop_async(class_name, spec))?
1002 }
1003
1004 #[doc(alias = "DbPutDeviceAttributeProperty2")]
1020 pub fn set_dev_attr_prop_async<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> impl Future<Output = Result<()>> + Send
1021 where
1022 Spec: SetAttrPropSpec<'a>,
1023 {
1024 self.prop_command_async("DbPutDeviceAttributeProperty2", attr_prop_params(dev_name, spec))
1025 }
1026
1027 #[doc(alias = "DbPutDeviceAttributeProperty2")]
1030 pub fn set_dev_attr_prop<'a, Spec>(&self, dev_name: &'a str, spec: Spec) -> Result<()>
1031 where
1032 Spec: SetAttrPropSpec<'a>,
1033 {
1034 self.block_on(self.set_dev_attr_prop_async(dev_name, spec))?
1035 }
1036
1037 #[doc(alias = "DbDeleteClassAttributeProperty")]
1042 pub fn delete_class_attr_prop_async<Names: ToNamesNotAll>(&self, class_name: &str, attr_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
1043 let params = prop_params(class_name, Some(attr_name).into_iter().chain(names.iter_names_not_all()));
1044 self.prop_command_async("DbDeleteClassAttributeProperty", params)
1045 }
1046
1047 #[doc(alias = "DbDeleteClassAttributeProperty")]
1050 pub fn delete_class_attr_prop<Names: ToNamesNotAll>(&self, class_name: &str, attr_name: &str, names: Names) -> Result<()> {
1051 self.block_on(self.delete_class_attr_prop_async(class_name, attr_name, names))?
1052 }
1053
1054 #[doc(alias = "DbDeleteDeviceAttributeProperty")]
1066 pub fn delete_dev_attr_prop_async<Names: ToNamesNotAll>(&self, dev_name: &str, attr_name: &str, names: Names) -> impl Future<Output = Result<()>> + Send {
1067 let params = prop_params(dev_name, Some(attr_name).into_iter().chain(names.iter_names_not_all()));
1068 self.prop_command_async("DbDeleteDeviceAttributeProperty", params)
1069 }
1070
1071 #[doc(alias = "DbDeleteDeviceAttributeProperty")]
1074 pub fn delete_dev_attr_prop<Names: ToNamesNotAll>(&self, dev_name: &str, attr_name: &str, names: Names) -> Result<()> {
1075 self.block_on(self.delete_dev_attr_prop_async(dev_name, attr_name, names))?
1076 }
1077
1078}
1079
1080impl Deref for DatabaseProxy {
1081 type Target = DevProxy;
1082 fn deref(&self) -> &Self::Target {
1083 &self.dev
1084 }
1085}
1086
1087impl DerefMut for DatabaseProxy {
1088 fn deref_mut(&mut self) -> &mut Self::Target {
1089 &mut self.dev
1090 }
1091}
1092
1093#[derive(Debug, Clone)]
1099pub struct ExportDevInfo<'a> {
1100 pub name: Cow<'a, str>,
1102 pub itr: Cow<'a, str>,
1104 pub host: Cow<'a, str>,
1106 pub version: Cow<'a, str>,
1108 pub pid: i32,
1110}
1111
1112fn data_from_export_dev_info(infos: &[ExportDevInfo<'_>]) -> Spectrum<str> {
1113
1114 let mut vec = Vec::with_capacity(infos.len() * 5);
1115
1116 for info in infos {
1117 vec.push(Cow::Borrowed(&*info.name));
1118 vec.push(Cow::Borrowed(&*info.itr));
1119 vec.push(Cow::Borrowed(&*info.host));
1120 vec.push(Cow::Owned(format!("{}", info.pid)));
1121 vec.push(Cow::Borrowed(&*info.version));
1122 }
1123
1124 Spectrum::from(&vec[..])
1125
1126}
1127
1128fn long2_string((longs, strings): (Spectrum<i32>, Spectrum<str>)) -> Result<([i32; 2], Spectrum<str>)> {
1131 let longs = <[i32; 2]>::try_from(longs.as_slice())
1132 .map_err(|_| Error::new(ErrorKind::InvalidData)
1133 .with_description(format!("Database answered {} longs where 2 were expected", longs.len()))
1134 .with_append_description(format_args!("Got: {longs:?}")))?;
1135 Ok((longs, strings))
1136}
1137
1138#[derive(Debug, Clone)]
1140pub struct ImportDevInfo {
1141 pub name: Scalar<str>,
1143 pub itr: Scalar<str>,
1145 pub host: Scalar<str>,
1147 pub version: Scalar<str>,
1149 pub server: Scalar<str>,
1151 pub class: Option<Scalar<str>>,
1153 pub exported: bool,
1155 pub pid: i32,
1157}
1158
1159#[derive(Debug, Clone)]
1161pub struct DbDevInfo {
1162 pub name: Scalar<str>,
1164 pub itr: Scalar<str>,
1166 pub host: Option<Scalar<str>>,
1168 pub version: Scalar<str>,
1170 pub server: Scalar<str>,
1172 pub class: Option<Scalar<str>>,
1174 pub last_exported: Option<Scalar<str>>, pub last_unexported: Option<Scalar<str>>, pub exported: bool,
1180 pub pid: Option<i32>,
1182}
1183
1184pub(crate) fn set_prop_params<'a, Spec: SetPropSpec<'a>>(spec: Spec) -> Vec<Cow<'a, str>> {
1197 let mut builder = set_prop::Builder::new();
1198 spec.push_to_builder(&mut builder);
1199 builder.finalize()
1200}
1201
1202pub(crate) fn prop_params<'a>(obj_name: &'a str, rest: impl Iterator<Item = &'a str>) -> Spectrum<str> {
1205 Spectrum::from_strs(Some(obj_name).into_iter().chain(rest)).expect("property parameters of more than 4 GiB")
1206}
1207
1208#[derive(Debug, Clone, Copy)]
1214pub(crate) struct PropCommands {
1215 get: &'static str,
1217 list: &'static str,
1219 list_wildcard: bool,
1221}
1222
1223impl PropCommands {
1224 const FREE: Self = Self { get: "DbGetProperty", list: "DbGetPropertyList", list_wildcard: true };
1225 const CLASS: Self = Self { get: "DbGetClassProperty", list: "DbGetClassPropertyList", list_wildcard: false };
1226 pub(crate) const DEV: Self = Self { get: "DbGetDeviceProperty", list: "DbGetDevicePropertyList", list_wildcard: true };
1227}
1228
1229mod get_prop {
1231
1232 use super::{Error, ErrorKind, Named, Result, Scalar, Spectrum};
1233
1234 #[derive(Debug)]
1240 pub enum PropReply {
1241 Listing {
1244 listing: Spectrum<str>,
1248 names: Spectrum<str>,
1251 index: usize,
1253 cursor: usize,
1255 },
1256 Attr {
1264 listing: Spectrum<str>,
1266 begin: usize,
1268 count: usize,
1270 names: Option<Spectrum<str>>,
1273 index: usize,
1275 cursor: usize,
1277 },
1278 }
1279
1280 impl PropReply {
1281
1282 pub(super) fn empty() -> Self {
1285 Self::Listing { listing: Spectrum::new(), names: Spectrum::new(), index: 0, cursor: 0 }
1286 }
1287
1288 pub(super) fn new(obj_name: &str, listing: Spectrum<str>, names: Spectrum<str>) -> Result<Self> {
1292 let cursor = read_head(&listing, obj_name, names.len(), "property count", "properties")?;
1293 Ok(Self::Listing { listing, names, index: 0, cursor })
1294 }
1295
1296 pub fn len(&self) -> usize {
1299 match self {
1300 Self::Listing { names, index, .. } => names.len() - index,
1301 Self::Attr { names: Some(names), index, .. } => names.len() - index,
1302 Self::Attr { names: None, count, index, .. } => count - index,
1303 }
1304 }
1305
1306 pub fn is_empty(&self) -> bool {
1308 self.len() == 0
1309 }
1310
1311 pub fn next(&mut self) -> Option<Result<Named<Spectrum<str>>>> {
1322
1323 let (listing, names, index, cursor) = match self {
1324 Self::Listing { listing, names, index, cursor } => (listing, names, index, cursor),
1325 Self::Attr { listing, begin, count, names, index, cursor } => {
1326 return next_attr_prop(listing, *begin, *count, names.as_ref(), index, cursor);
1327 }
1328 };
1329
1330 let expected = names.get([*index])?;
1331 *index += 1;
1332
1333 match next_prop(listing, expected, cursor) {
1334 Ok(prop) => Some(Ok(prop)),
1335 Err(err) => {
1336 *index = names.len();
1337 Some(Err(err))
1338 }
1339 }
1340
1341 }
1342
1343 }
1344
1345 fn next_prop(listing: &Spectrum<str>, expected: &str, cursor: &mut usize) -> Result<Named<Spectrum<str>>> {
1351
1352 let (Some(name), Some(count_raw)) = (listing.get([*cursor]), listing.get([*cursor + 1])) else {
1353 return Err(Error::new(ErrorKind::InvalidData)
1354 .with_description(format!("Database answer is missing the name and values count of property {expected:?}"))
1355 .with_append_description(format_args!("Got: {listing:?}")));
1356 };
1357
1358 if !name.eq_ignore_ascii_case(expected) {
1359 return Err(Error::new(ErrorKind::InvalidData)
1360 .with_description(format!("Database answered property {name:?} where {expected:?} was requested")));
1361 }
1362
1363 let Ok(count) = count_raw.parse::<usize>() else {
1364 return Err(Error::new(ErrorKind::InvalidData)
1365 .with_description(format!("Database answered values count {count_raw:?} of property {name:?}, which is not a number")));
1366 };
1367
1368 let name_index = *cursor;
1369 let begin = *cursor + 2;
1370 *cursor = begin + count;
1371
1372 if *cursor > listing.len() {
1373 return Err(Error::new(ErrorKind::InvalidData)
1374 .with_description(format!("Database answer is missing values of property {name:?}"))
1375 .with_append_description(format_args!("Got: {listing:?}")));
1376 }
1377
1378 let name = listing.slice(name_index..name_index + 1).into_scalar().expect("one name");
1379 Ok(Named::new(name, listing.slice(begin..*cursor)))
1380
1381 }
1382
1383 fn next_attr_prop(
1390 listing: &Spectrum<str>,
1391 begin: usize,
1392 count: usize,
1393 names: Option<&Spectrum<str>>,
1394 index: &mut usize,
1395 cursor: &mut usize,
1396 ) -> Option<Result<Named<Spectrum<str>>>> {
1397
1398 let Some(names) = names else {
1399 if *index >= count {
1400 return None;
1401 }
1402 *index += 1;
1403 return Some(next_value_prop(listing, cursor));
1404 };
1405
1406 let name = names.get_scalar([*index])?;
1407 *index += 1;
1408
1409 let mut lookup = begin;
1410 for _ in 0..count {
1411 match next_value_prop(listing, &mut lookup) {
1412 Ok(prop) if prop.name.value().eq_ignore_ascii_case(name.value()) => {
1413 return Some(Ok(prop));
1414 }
1415 Ok(_) => {}
1416 Err(err) => {
1417 *index = names.len();
1418 return Some(Err(err));
1419 }
1420 }
1421 }
1422
1423 Some(Ok(Named::new(name, Spectrum::new())))
1424
1425 }
1426
1427 fn next_value_prop(listing: &Spectrum<str>, cursor: &mut usize) -> Result<Named<Spectrum<str>>> {
1432
1433 let name = next_str(listing, cursor, "property name")?;
1434 let count = next_count(listing, cursor, "property values count")?;
1435
1436 let begin = *cursor;
1437 *cursor += count.max(1);
1438 if *cursor > listing.len() {
1439 return Err(Error::new(ErrorKind::InvalidData)
1440 .with_description(format!("Database answer is missing values of property {:?}", name.value()))
1441 .with_append_description(format_args!("Got: {listing:?}")));
1442 }
1443
1444 Ok(Named::new(name, listing.slice(begin..begin + count)))
1445
1446 }
1447
1448 #[derive(Debug)]
1455 pub struct AttrPropReply {
1456 listing: Spectrum<str>,
1458 attr_names: Spectrum<str>,
1461 prop_names: Option<Spectrum<str>>,
1463 index: usize,
1465 cursor: usize,
1467 }
1468
1469 impl AttrPropReply {
1470
1471 pub(super) fn empty() -> Self {
1474 Self { listing: Spectrum::new(), attr_names: Spectrum::new(), prop_names: None, index: 0, cursor: 0 }
1475 }
1476
1477 pub(super) fn new(
1481 obj_name: &str,
1482 listing: Spectrum<str>,
1483 attr_names: Spectrum<str>,
1484 prop_names: Option<Spectrum<str>>,
1485 ) -> Result<Self> {
1486 let cursor = read_head(&listing, obj_name, attr_names.len(), "attribute count", "attributes")?;
1487 Ok(Self { listing, attr_names, prop_names, index: 0, cursor })
1488 }
1489
1490 pub fn len(&self) -> usize {
1492 self.attr_names.len() - self.index
1493 }
1494
1495 pub fn next(&mut self) -> Option<Result<Named<PropReply>>> {
1501
1502 let Self { listing, attr_names, prop_names, index, cursor } = self;
1503
1504 let expected = attr_names.get([*index])?;
1505 *index += 1;
1506
1507 let res = (|| {
1508
1509 let name = next_str(listing, cursor, "attribute name")?;
1510 if !name.value().eq_ignore_ascii_case(expected) {
1511 return Err(Error::new(ErrorKind::InvalidData)
1512 .with_description(format!("Database answered attribute {:?} where {expected:?} was requested",
1513 name.value())));
1514 }
1515
1516 let count = next_count(listing, cursor, "property count")?;
1519 let begin = *cursor;
1520 for _ in 0..count {
1521 next_value_prop(listing, cursor)?;
1522 }
1523
1524 Ok(Named::new(name, PropReply::Attr {
1525 listing: listing.clone(),
1526 begin,
1527 count,
1528 names: prop_names.clone(),
1529 index: 0,
1530 cursor: begin,
1531 }))
1532
1533 })();
1534
1535 if res.is_err() {
1536 *index = attr_names.len();
1537 }
1538
1539 Some(res)
1540
1541 }
1542
1543 }
1544
1545 fn read_head(listing: &Spectrum<str>, obj_name: &str, expected: usize, what: &str, entries: &str) -> Result<usize> {
1548
1549 let mut cursor = 0;
1550
1551 let output_obj_name = next_str(listing, &mut cursor, "object name")?;
1552 if !output_obj_name.value().eq_ignore_ascii_case(obj_name) {
1553 return Err(Error::new(ErrorKind::InvalidData)
1554 .with_description(format!("Database answered for object {:?} where {obj_name:?} was requested",
1555 output_obj_name.value())));
1556 }
1557
1558 let count = next_count(listing, &mut cursor, what)?;
1559 if count != expected {
1560 return Err(Error::new(ErrorKind::InvalidData)
1561 .with_description(format!("Database answered {count} {entries} of object {obj_name:?} where {expected} were requested")));
1562 }
1563
1564 Ok(cursor)
1565
1566 }
1567
1568 fn next_str(listing: &Spectrum<str>, cursor: &mut usize, what: &str) -> Result<Scalar<str>> {
1570 let Some(value) = listing.get_scalar([*cursor]) else {
1571 return Err(Error::new(ErrorKind::InvalidData)
1572 .with_description(format!("Database answer is missing the {what}"))
1573 .with_append_description(format_args!("Got: {listing:?}")));
1574 };
1575 *cursor += 1;
1576 Ok(value)
1577 }
1578
1579 fn next_count(listing: &Spectrum<str>, cursor: &mut usize, what: &str) -> Result<usize> {
1581 let raw = next_str(listing, cursor, what)?;
1582 raw.value().trim().parse::<usize>().map_err(|_| Error::new(ErrorKind::InvalidData)
1583 .with_description(format!("Database answered {what} {:?}, which is not a number", raw.value())))
1584 }
1585
1586}
1587
1588pub trait GetPropSpec<Names> {
1594
1595 type Output;
1597
1598 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output>;
1603
1604}
1605
1606impl<T> GetPropSpec<&'_ str> for T
1609where
1610 T: FromProp,
1611{
1612
1613 type Output = T;
1614
1615 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1616 match props.next() {
1617 Some(entry) => T::from_prop(&entry?.value),
1618 None => Err(unexpected_len_err(1)),
1619 }
1620 }
1621
1622}
1623
1624impl<T> GetPropSpec<&'_ [&'_ str]> for T
1625where
1626 T: FromProp,
1627{
1628
1629 type Output = Vec<Result<T>>;
1630
1631 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1632
1633 let mut values = Vec::with_capacity(props.len());
1636
1637 while let Some(entry) = props.next() {
1638 values.push(T::from_prop(&entry?.value));
1639 }
1640
1641 Ok(values)
1642
1643 }
1644
1645}
1646
1647impl<T> GetPropSpec<Spectrum<str>> for T
1648where
1649 T: FromProp,
1650{
1651
1652 type Output = Vec<Result<T>>;
1653
1654 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1655 <T as GetPropSpec<&[&str]>>::collect(props)
1656 }
1657
1658}
1659
1660impl<T> GetPropSpec<&Spectrum<str>> for T
1661where
1662 T: FromProp,
1663{
1664
1665 type Output = Vec<Result<T>>;
1666
1667 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1668 <T as GetPropSpec<&[&str]>>::collect(props)
1669 }
1670
1671}
1672
1673impl<T, const N: usize> GetPropSpec<[&'_ str; N]> for T
1674where
1675 T: FromProp,
1676{
1677
1678 type Output = [Result<T>; N];
1679
1680 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1681
1682 let mut slots = [const { None }; N];
1685 for slot in &mut slots {
1686 let entry = props.next().ok_or_else(|| unexpected_len_err(N))?;
1687 *slot = Some(T::from_prop(&entry?.value));
1688 }
1689 if props.next().is_some() {
1690 return Err(unexpected_len_err(N));
1691 }
1692
1693 Ok(slots.map(|slot| slot.expect("every slot is filled")))
1694
1695 }
1696
1697}
1698
1699impl GetPropSpec<All> for Spectrum<str> {
1700
1701 type Output = Vec<Named<Spectrum<str>>>;
1702
1703 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1704
1705 let mut values = Vec::with_capacity(props.len());
1708
1709 while let Some(entry) = props.next() {
1710 values.push(entry?);
1711 }
1712
1713 Ok(values)
1714
1715 }
1716
1717}
1718
1719macro_rules! impl_get_prop_spec_tuple {
1720 ( @one: $comp:ident ) => { 1 };
1721 ( @name: $comp:ident ) => { &'name str };
1722 ( $( $comp:ident )* ) => {
1723
1724 #[allow(non_snake_case)]
1725 impl<'name, $($comp,)* > GetPropSpec<( $( impl_get_prop_spec_tuple!(@name: $comp), )* )> for ( $($comp,)* )
1726 where
1727 $(
1728 $comp: FromProp,
1729 )*
1730 {
1731
1732 type Output = ( $( Result<$comp>,)* );
1733
1734 fn collect(props: &mut get_prop::PropReply) -> Result<Self::Output> {
1735
1736 const LEN: usize = 0 $( + impl_get_prop_spec_tuple!(@one: $comp) )*;
1737
1738 let output = ( $( {
1742 let entry = props.next().ok_or_else(|| unexpected_len_err(LEN))?;
1743 $comp::from_prop(&entry?.value)
1744 }, )* );
1745 if props.next().is_some() {
1746 return Err(unexpected_len_err(LEN));
1747 }
1748
1749 Ok(output)
1750
1751 }
1752
1753 }
1754
1755 };
1756}
1757
1758impl_get_prop_spec_tuple!(A);
1759impl_get_prop_spec_tuple!(A B);
1760impl_get_prop_spec_tuple!(A B C);
1761impl_get_prop_spec_tuple!(A B C D);
1762impl_get_prop_spec_tuple!(A B C D E);
1763impl_get_prop_spec_tuple!(A B C D E F);
1764
1765mod set_prop {
1771
1772 use super::{Cow, IntoProp, SetPropSpec};
1773
1774 pub struct Builder<'a> {
1775 array: Vec<Cow<'a, str>>,
1776 count: usize,
1777 }
1778
1779 impl<'a> Builder<'a> {
1780
1781 pub fn new() -> Self {
1782 Self {
1783 array: vec![Cow::Borrowed("")], count: 0,
1785 }
1786 }
1787
1788 pub fn push<T>(&mut self, name: &'a str, value: T)
1789 where
1790 T: IntoProp<'a>,
1791 {
1792 self.array.push(Cow::Borrowed(name));
1793 self.array.push(Cow::Borrowed("")); let len = self.array.len();
1795 self.array.extend(value.into_prop());
1796 let count = self.array.len() - len;
1797 self.array[len - 1] = Cow::Owned(format!("{count}")); self.count += 1;
1799 }
1800
1801 pub fn finalize(mut self) -> Vec<Cow<'a, str>> {
1802 self.array[0] = Cow::Owned(format!("{}", self.count));
1804 self.array
1805 }
1806
1807 }
1808
1809 pub struct AttrBuilder<'a> {
1812 array: Vec<Cow<'a, str>>,
1813 count: usize,
1814 }
1815
1816 impl<'a> AttrBuilder<'a> {
1817
1818 pub fn new() -> Self {
1819 Self {
1820 array: vec![Cow::Borrowed("")], count: 0,
1822 }
1823 }
1824
1825 pub fn push<S>(&mut self, attr_name: &'a str, spec: S)
1826 where
1827 S: SetPropSpec<'a>,
1828 {
1829 let mut builder = Builder::new();
1830 spec.push_to_builder(&mut builder);
1831 self.array.push(Cow::Borrowed(attr_name));
1832 self.array.extend(builder.finalize());
1833 self.count += 1;
1834 }
1835
1836 pub fn finalize(mut self) -> Vec<Cow<'a, str>> {
1837 self.array[0] = Cow::Owned(format!("{}", self.count));
1838 self.array
1839 }
1840
1841 }
1842
1843}
1844
1845pub trait SetPropSpec<'a>: Sized {
1850 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>);
1852}
1853
1854impl<'a, T> SetPropSpec<'a> for (&'a str, T)
1856where
1857 T: IntoProp<'a>,
1858{
1859
1860 #[inline]
1861 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1862 builder.push(self.0, self.1);
1863 }
1864
1865}
1866
1867impl<'a, T, const N: usize> SetPropSpec<'a> for [(&'a str, T); N]
1869where
1870 T: IntoProp<'a>,
1871{
1872
1873 #[inline]
1874 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1875 for (name, value) in self {
1876 builder.push(name, value);
1877 }
1878 }
1879
1880}
1881
1882impl<'a, 'aa: 'a, T> SetPropSpec<'a> for Vec<(&'aa str, T)>
1884where
1885 T: IntoProp<'a>,
1886{
1887
1888 #[inline]
1889 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1890 for (name, value) in self {
1891 builder.push(name, value);
1892 }
1893 }
1894
1895}
1896
1897macro_rules! impl_set_prop_spec_tuple {
1898 ( @name: $comp:ident ) => { &'a str };
1899 ( $( $comp:ident )* ) => {
1900
1901 #[allow(non_snake_case, unused_assignments)]
1902 impl<'a, $($comp,)*> SetPropSpec<'a> for ( $( (impl_set_prop_spec_tuple!(@name: $comp), $comp), )* )
1903 where
1904 $(
1905 $comp: IntoProp<'a>,
1906 )*
1907 {
1908
1909 #[inline]
1910 fn push_to_builder(self, builder: &mut set_prop::Builder<'a>) {
1911 let ( $($comp,)* ) = self;
1912 $(
1913 builder.push($comp.0, $comp.1);
1914 )*
1915 }
1916
1917 }
1918
1919 };
1920}
1921
1922impl_set_prop_spec_tuple!(A);
1923impl_set_prop_spec_tuple!(A B);
1924impl_set_prop_spec_tuple!(A B C);
1925impl_set_prop_spec_tuple!(A B C D);
1926impl_set_prop_spec_tuple!(A B C D E);
1927impl_set_prop_spec_tuple!(A B C D E F);
1928
1929#[derive(Debug, Clone, Copy)]
1935pub(crate) struct AttrPropCommands {
1936 get: &'static str,
1938 list: &'static str,
1940}
1941
1942impl AttrPropCommands {
1943 pub(crate) const CLASS: Self = Self { get: "DbGetClassAttributeProperty2", list: "DbGetClassAttributeList" };
1944 pub(crate) const DEV: Self = Self { get: "DbGetDeviceAttributeProperty2", list: "DbGetDeviceAttributeList" };
1945}
1946
1947pub trait GetAttrPropSpec<AttrNames, Names> {
1956
1957 type Output;
1959
1960 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output>;
1963
1964}
1965
1966fn next_attr<T: GetPropSpec<Names>, Names>(attrs: &mut get_prop::AttrPropReply) -> Option<Result<NamedResult<T::Output>>> {
1969 Some(attrs.next()?.map(|attr| attr.map(|mut props| T::collect(&mut props))))
1970}
1971
1972impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ str, Names> for T {
1975
1976 type Output = T::Output;
1977
1978 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
1979 match next_attr::<T, Names>(attrs) {
1980 Some(attr) => attr?.value,
1981 None => Err(unexpected_len_err(1)),
1982 }
1983 }
1984
1985}
1986
1987fn collect_attr_list<T: GetPropSpec<Names>, Names>(attrs: &mut get_prop::AttrPropReply) -> Result<Vec<Result<T::Output>>> {
1989 let mut outputs = Vec::with_capacity(attrs.len());
1990 while let Some(attr) = next_attr::<T, Names>(attrs) {
1991 outputs.push(attr?.value);
1992 }
1993 Ok(outputs)
1994}
1995
1996impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ [&'_ str], Names> for T {
1997 type Output = Vec<Result<T::Output>>;
1998 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
1999 collect_attr_list::<T, Names>(attrs)
2000 }
2001}
2002
2003impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<Spectrum<str>, Names> for T {
2004 type Output = Vec<Result<T::Output>>;
2005 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2006 collect_attr_list::<T, Names>(attrs)
2007 }
2008}
2009
2010impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<&'_ Spectrum<str>, Names> for T {
2011 type Output = Vec<Result<T::Output>>;
2012 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2013 collect_attr_list::<T, Names>(attrs)
2014 }
2015}
2016
2017impl<T: GetPropSpec<Names>, Names, const N: usize> GetAttrPropSpec<[&'_ str; N], Names> for T {
2018
2019 type Output = [Result<T::Output>; N];
2020
2021 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2022 let mut slots = [const { None }; N];
2025 for slot in &mut slots {
2026 *slot = Some(next_attr::<T, Names>(attrs).ok_or_else(|| unexpected_len_err(N))??.value);
2027 }
2028 if attrs.next().is_some() {
2029 return Err(unexpected_len_err(N));
2030 }
2031 Ok(slots.map(|slot| slot.expect("every slot is filled")))
2032 }
2033
2034}
2035
2036impl<T: GetPropSpec<Names>, Names> GetAttrPropSpec<All, Names> for T {
2038
2039 type Output = Vec<NamedResult<T::Output>>;
2040
2041 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2042 let mut outputs = Vec::with_capacity(attrs.len());
2043 while let Some(attr) = next_attr::<T, Names>(attrs) {
2044 outputs.push(attr?);
2045 }
2046 Ok(outputs)
2047 }
2048
2049}
2050
2051macro_rules! impl_get_attr_prop_spec_tuple {
2052 ( @one: $index:tt ) => { 1 };
2053 ( @name: $index:tt ) => { &'name str };
2054 ( @output: $index:tt ) => { Result<T::Output> };
2055 ( @next: $index:tt, $attrs:ident ) => { next_attr::<T, Names>($attrs).ok_or_else(|| unexpected_len_err(LEN))??.value };
2056 ( $( $index:tt )* ) => {
2057
2058 impl<'name, T: GetPropSpec<Names>, Names> GetAttrPropSpec<( $( impl_get_attr_prop_spec_tuple!(@name: $index), )* ), Names> for T {
2059
2060 type Output = ( $( impl_get_attr_prop_spec_tuple!(@output: $index), )* );
2061
2062 fn collect(attrs: &mut get_prop::AttrPropReply) -> Result<Self::Output> {
2063 const LEN: usize = 0 $( + impl_get_attr_prop_spec_tuple!(@one: $index) )*;
2064 let output = ( $( impl_get_attr_prop_spec_tuple!(@next: $index, attrs), )* );
2067 if attrs.next().is_some() {
2068 return Err(unexpected_len_err(LEN));
2069 }
2070 Ok(output)
2071 }
2072
2073 }
2074
2075 };
2076}
2077
2078impl_get_attr_prop_spec_tuple!(0);
2079impl_get_attr_prop_spec_tuple!(0 1);
2080impl_get_attr_prop_spec_tuple!(0 1 2);
2081impl_get_attr_prop_spec_tuple!(0 1 2 3);
2082impl_get_attr_prop_spec_tuple!(0 1 2 3 4);
2083impl_get_attr_prop_spec_tuple!(0 1 2 3 4 5);
2084
2085pub trait SetAttrPropSpec<'a>: Sized {
2096 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>);
2098}
2099
2100impl<'a, S> SetAttrPropSpec<'a> for (&'a str, S)
2102where
2103 S: SetPropSpec<'a>,
2104{
2105
2106 #[inline]
2107 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2108 builder.push(self.0, self.1);
2109 }
2110
2111}
2112
2113impl<'a, S, const N: usize> SetAttrPropSpec<'a> for [(&'a str, S); N]
2115where
2116 S: SetPropSpec<'a>,
2117{
2118
2119 #[inline]
2120 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2121 for (attr_name, spec) in self {
2122 builder.push(attr_name, spec);
2123 }
2124 }
2125
2126}
2127
2128impl<'a, S> SetAttrPropSpec<'a> for Vec<(&'a str, S)>
2130where
2131 S: SetPropSpec<'a>,
2132{
2133
2134 #[inline]
2135 fn push_to_builder(self, builder: &mut set_prop::AttrBuilder<'a>) {
2136 for (attr_name, spec) in self {
2137 builder.push(attr_name, spec);
2138 }
2139 }
2140
2141}
2142
2143fn attr_prop_params<'a, Spec: SetAttrPropSpec<'a>>(obj_name: &str, spec: Spec) -> Spectrum<str> {
2145 let mut builder = set_prop::AttrBuilder::new();
2146 spec.push_to_builder(&mut builder);
2147 prop_params(obj_name, builder.finalize().iter().map(|param| &**param))
2148}
2149
2150#[cfg(test)]
2151mod tests {
2152
2153 use futures::future::BoxFuture;
2154
2155 use super::*;
2156
2157 #[allow(dead_code)]
2160 fn attr_props_in_send_future(db: &DatabaseProxy) -> BoxFuture<'_, Result<()>> {
2161 Box::pin(async move {
2162 let _ = db.get_dev_attr_prop_async::<f64, _, _>("motor/dev/1", "Position", "max_value").await?;
2163 let _ = db.get_class_attr_prop_async::<(String, f64), _, _>("Motor", ["Position"], ("label", "max_value")).await?;
2164 let _ = db.get_dev_attr_prop_async::<Spectrum<str>, _, _>("motor/dev/1", All, All).await?;
2165 Ok(())
2166 })
2167 }
2168
2169 fn reply(names: &[&str], listing: &[&str]) -> get_prop::PropReply {
2174 get_prop::PropReply::new(listing[0], Spectrum::from(listing), Spectrum::from(names)).unwrap()
2175 }
2176
2177 fn attr_reply(attr_names: &[&str], prop_names: Option<&[&str]>, listing: &[&str]) -> get_prop::AttrPropReply {
2181 get_prop::AttrPropReply::new(listing[0], Spectrum::from(listing), Spectrum::from(attr_names), prop_names.map(Spectrum::from)).unwrap()
2182 }
2183
2184 #[test]
2188 fn listing_head() {
2189
2190 let names = || Spectrum::from(&["prop"][..]);
2191
2192 let err = get_prop::PropReply::new("obj", Spectrum::from(&["another", "1", "prop", "0"][..]), names()).unwrap_err();
2193 assert_eq!(err.kind(), ErrorKind::InvalidData);
2194 let err = get_prop::PropReply::new("obj", Spectrum::from(&["obj", "2", "prop", "0"][..]), names()).unwrap_err();
2195 assert_eq!(err.kind(), ErrorKind::InvalidData);
2196 let err = get_prop::AttrPropReply::new("obj", Spectrum::from(&["obj", "2", "prop", "0"][..]), names(), None).unwrap_err();
2197 assert_eq!(err.kind(), ErrorKind::InvalidData);
2198
2199 let mut props = get_prop::PropReply::empty();
2200 assert!(props.is_empty());
2201 assert!(props.next().is_none());
2202 let mut attrs = get_prop::AttrPropReply::empty();
2203 assert_eq!(attrs.len(), 0);
2204 assert!(attrs.next().is_none());
2205
2206 }
2207
2208 fn attr_props(props: &mut get_prop::PropReply) -> Vec<(String, Vec<String>)> {
2210 let mut taken = Vec::new();
2211 while let Some(prop) = props.next() {
2212 let prop = prop.unwrap();
2213 taken.push((prop.name.value().to_string(), prop.value.iter().map(str::to_string).collect()));
2214 }
2215 taken
2216 }
2217
2218 const ATTR_LISTING: &[&str] = &[
2219 "sys/tg_test/1", "3",
2220 "first", "2", "label", "1", "First", "rel_change", "2", "-1", "2",
2221 "empty", "1", "unit", "0", " ",
2222 "none", "0",
2223 ];
2224
2225 #[test]
2230 fn attr_props_in_order() {
2231
2232 let mut reply = attr_reply(&["first", "empty", "none"], None, ATTR_LISTING);
2233 assert_eq!(reply.len(), 3);
2234
2235 let Named { name, value: mut props } = reply.next().unwrap().unwrap();
2236 assert_eq!(name.value(), "first");
2237 assert_eq!(props.len(), 2);
2238 assert_eq!(attr_props(&mut props), [
2239 ("label".to_string(), vec!["First".to_string()]),
2240 ("rel_change".to_string(), vec!["-1".to_string(), "2".to_string()]),
2241 ]);
2242
2243 let mut props = reply.next().unwrap().unwrap().value;
2244 assert_eq!(attr_props(&mut props), [("unit".to_string(), vec![])]);
2245
2246 let mut props = reply.next().unwrap().unwrap().value;
2247 assert!(attr_props(&mut props).is_empty());
2248
2249 assert!(reply.next().is_none());
2250
2251 }
2252
2253 #[test]
2256 fn attr_prop_lookup() {
2257
2258 let mut reply = attr_reply(&["first", "empty", "none"], Some(&["REL_CHANGE", "unit"]), ATTR_LISTING);
2259
2260 let mut props = reply.next().unwrap().unwrap().value;
2261 assert_eq!(props.len(), 2);
2262 assert_eq!(attr_props(&mut props), [
2263 ("rel_change".to_string(), vec!["-1".to_string(), "2".to_string()]),
2264 ("unit".to_string(), vec![]),
2265 ]);
2266
2267 let mut props = reply.next().unwrap().unwrap().value;
2268 assert_eq!(attr_props(&mut props), [
2269 ("REL_CHANGE".to_string(), vec![]),
2270 ("unit".to_string(), vec![]),
2271 ]);
2272
2273 }
2274
2275 #[test]
2279 fn incoherent_attr_props() {
2280
2281 let mut reply = attr_reply(&["asked", "behind"], None, &["obj", "2", "another", "0", "behind", "0"]);
2282 assert_eq!(reply.next().unwrap().unwrap_err().kind(), ErrorKind::InvalidData);
2283 assert!(reply.next().is_none());
2284
2285 let mut reply = attr_reply(&["asked"], None, &["obj", "1", "asked", "1", "label", "2", "one"]);
2286 assert_eq!(reply.next().unwrap().unwrap_err().kind(), ErrorKind::InvalidData);
2287
2288 }
2289
2290 #[test]
2294 fn attr_prop_write() {
2295 let params = attr_prop_params("obj", [
2296 ("first", vec![("label", "First"), ("unit", "mm")]),
2297 ("second", vec![("label", "Second")]),
2298 ]);
2299 assert_eq!(params.iter().collect::<Vec<_>>(), [
2300 "obj", "2",
2301 "first", "2", "label", "1", "First", "unit", "1", "mm",
2302 "second", "1", "label", "1", "Second",
2303 ]);
2304 }
2305
2306 #[test]
2309 fn props_in_order() {
2310
2311 let mut props = reply(&["first", "second"],
2312 &["sys/tg_test/1", "2", "first", "1", "one", "second", "2", "two", "three"]);
2313
2314 assert_eq!(props.len(), 2);
2315
2316 let Named { name, value: values } = props.next().unwrap().unwrap();
2317 assert_eq!(name.value(), "first");
2318 assert_eq!(values.iter().collect::<Vec<_>>(), ["one"]);
2319
2320 let Named { name, value: values } = props.next().unwrap().unwrap();
2321 assert_eq!(name.value(), "second");
2322 assert_eq!(values.iter().collect::<Vec<_>>(), ["two", "three"]);
2323
2324 assert!(props.next().is_none());
2325
2326 }
2327
2328 #[test]
2331 fn prop_without_value() {
2332 let mut props = reply(&["empty"], &["obj", "1", "empty", "0"]);
2333 let Named { name, value: values } = props.next().unwrap().unwrap();
2334 assert_eq!(name.value(), "empty");
2335 assert!(values.is_empty());
2336 }
2337
2338 #[test]
2341 fn incoherent_prop_name() {
2342 let mut props = reply(&["asked"], &["obj", "1", "another", "1", "one"]);
2343 let err = props.next().unwrap().unwrap_err();
2344 assert_eq!(err.kind(), ErrorKind::InvalidData);
2345 }
2346
2347 #[test]
2352 fn missing_prop_values() {
2353 let mut props = reply(&["prop", "behind"], &["obj", "2", "prop", "2", "one"]);
2354 let err = props.next().unwrap().unwrap_err();
2355 assert_eq!(err.kind(), ErrorKind::InvalidData);
2356 assert!(props.next().is_none());
2357 }
2358
2359 #[test]
2362 fn single_prop_parsed() {
2363 let mut props = reply(&["prop"], &["obj", "1", "prop", "1", "3.5"]);
2364 let value = <f64 as GetPropSpec<&str>>::collect(&mut props).unwrap();
2365 assert_eq!(value, 3.5);
2366 }
2367
2368}