Skip to content
This repository has been archived by the owner on May 11, 2023. It is now read-only.

Array should provide concrete-type element getters #273

Open
zeenix opened this issue Apr 20, 2022 · 9 comments
Open

Array should provide concrete-type element getters #273

zeenix opened this issue Apr 20, 2022 · 9 comments
Labels
api break zvariant Issues/PRs related to zvariant crate

Comments

@zeenix
Copy link
Collaborator

zeenix commented Apr 20, 2022

In GitLab by @WhyNotHugo on Apr 20, 2022, 23:52

I need to create an array with a struct. I basically, want to do this:

STRUCT "sv" {
        STRING "ExecStart";
        VARIANT "a(sasb)" {
                ARRAY "(sasb)" {
                        STRUCT "sasb" {
                                STRING "alacritty";
                                ARRAY "s" {
                                        STRING "alacritty";
                                };
                                BOOLEAN true;
                        };
                };
        };
};

But Array seems to assume that only Variants will be put into it, so I've only been able to construct arrays with variant(struct), which is not entirely the same.

Is this possible an oversight in the API?

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 20, 2022

But Array seems to assume that only Variants will be put into it, so I've only been able to construct arrays with variant(struct), which is not entirely the same.

Array is for arrays in a Value (as in VARIANT type in D-Bus). For just arrays, you just use Vec or slice.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 20, 2022

Actually look at the code again, Array only keeps the elements as Value to allow arbitrary types dynamically. All elements are however, expected to be the same type and encoded/decoded as such. There are conversions provided to convert between Vec and Array but also between Vec and Value directly so you rarely need to use Array directly.

Having said that, I think it's a bit of an oversight that Array::get gets you all elements as Value but Dict::get gets you a specific element and converts it into a concrete type for you. At least Array should provide a way to get an element with a concrete type.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

In GitLab by @WhyNotHugo on Apr 21, 2022, 12:19

Right, so it seems that if I want an array of non-variants, I need to use Array::new and pass a signature. It works, but it's eventually pretty ugly:

    let es = Structure::from((command[0].clone(), command, true));

    let mut a = Array::new(Signature::try_from("(sasb)").unwrap());
    a.append(Value::Structure(es)).unwrap();

    let props: Vec<(&str, Value)> = vec![
        ("ExecStart", Value::Array(a)),
    ];

Array generics

I think it really makes sense for Array to be a generic type, so I can use Array<Mysig>. This would allow something like:

let a : Array<MySignature> = vec!(...).into();

Note that an Array<Variant> would still be valid (for arrays with mixed variant types).

Signature macro

That aside, a macro for Signature would be super useful; if the signature string is invalid, I'd prefer a compile-time failure in this case, and not a runtime failure.

Both together would allow for something nice and simple (but also more compile-time validations):

let a : Array<signature!("(sasb)")> = vec!(...).into

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

Right, so it seems that if I want an array of non-variants, I need to use Array::new and pass a signature. It works, but it's eventually pretty ugly:

but why don't use use a Vec instead? If you need to put it into a variant, you can convert back and forth to/from a Value.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

As I wrote, need to use Array directly should be very rare.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

And Array can't be a generic type, because that'd need Value to be a generic type too and that couldn't work for various reasons.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

In GitLab by @WhyNotHugo on Apr 21, 2022, 18:45

I haven't been able to use Vec directly.

Using a Vec<Structure> (e.g.: let a = vec!(es);):

error[E0308]: mismatched types
  --> src/main.rs:71:36
   |
71 |         ("ExecStart", Value::Array(a)),
   |                                    ^ expected struct `zbus::zvariant::Array`, found struct `Vec`
   |
   = note: expected struct `zbus::zvariant::Array<'_>`
              found struct `Vec<zbus::zvariant::Structure<'_>>`
error[E0277]: the trait bound `zbus::zvariant::Structure<'_>: Type` is not satisfied
  --> src/main.rs:71:38
   |
71 |         ("ExecStart", Value::Array(a.into())),
   |                                      ^^^^ the trait `Type` is not implemented for `zbus::zvariant::Structure<'_>`
   |
   = note: required because of the requirements on the impl of `From<Vec<zbus::zvariant::Structure<'_>>>` for `zbus::zvariant::Array<'_>`
   = note: required because of the requirements on the impl of `Into<zbus::zvariant::Array<'_>>` for `Vec<zbus::zvariant::Structure<'_>>`

Using let a = vec!(Value::from(es)); builds, but sends an array of variants,
not an array of structs, so it's the wrong data type an doesn't work.

I can't get an array of non-variants to work. I don't see how it's possible;
once data is put into an array, some information is lost. Specifically, when
later serialising there's no way to determine if it's an array of structs, or
an array of variants [which are structs].


And Array can't be a generic type, because that'd need Value to be a generic type too and that couldn't work for various reasons.

I think my idea was not clear: Array can be generic in the sense that one can
use something like:

array_of_ints: Array<u32>
array_of_structs: Array<Structure>
array_of_variants: Array<Value>

The generic parameter for array would just need to implement the Into<Value>
trait.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

Using a Vec<Structure> (e.g.: let a = vec!(es);):

Same thing about Structure, you're not expected to be using it directly. Use a struct or tuple directly if you need that.

@zeenix
Copy link
Collaborator Author

zeenix commented Apr 21, 2022

In GitLab by @WhyNotHugo on Apr 21, 2022, 21:13

Ooooh! This turned out to be so much simpler!

    let exec_start = (command[0].clone(), command, true);

    let props: Vec<(&str, Value)> = vec![
        ("RemainAfterExit", remain_after_exit.into()),
        ("ExecStart", vec![exec_start].into()),
        ("ExitType", exit_type.to_string().into()),
    ];

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api break zvariant Issues/PRs related to zvariant crate
Projects
None yet
Development

No branches or pull requests

1 participant