Bug 93912 - Name of struct members in introspection data
Summary: Name of struct members in introspection data
Status: RESOLVED MOVED
Alias: None
Product: dbus
Classification: Unclassified
Component: core (show other bugs)
Version: unspecified
Hardware: Other All
: medium enhancement
Assignee: D-Bus Maintainers
QA Contact: D-Bus Maintainers
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-01-28 22:12 UTC by Martin Ejdestig
Modified: 2018-10-12 21:26 UTC (History)
1 user (show)

See Also:
i915 platform:
i915 features:


Attachments

Description Martin Ejdestig 2016-01-28 22:12:56 UTC
To allow for code generators to generate more structured code (e.g. structs/classes in C/C++) and for tools that are used to introspect D-Bus to present structs to the user in a more descriptive way.

When searching for how to do this in D-Bus in came across this page:

https://wiki.allseenalliance.org/irb/extended_introspection_xml

Allows for XML looking like this:

<struct name="ObjectDescription">
  <field name="path" type="o"/>
  <field name="interfaces" type="as"/>
</struct>
<method name="GetObjectDescription">
  <arg name="objectDescription" type="a[ObjectDescription]" direction="out"/>
</method>
Comment 1 Martin Ejdestig 2016-01-28 22:17:59 UTC
s/in D-Bus in/in D-Bus I/
Comment 2 Thiago Macieira 2016-01-28 22:56:50 UTC
Good idea. But I'd require the type to remain as-is, with the current signature, for backwards compatibility. Add a new attribute to the <arg> and to <property> containing the extended type information.

I'd require that if it's used, then it needs to name the outermost structure. That would prevent things like "([Point]a{sv}[Point][Rect]is)". That is, "(" and "[" cannot appear both in the same single-type signature.

Also wondering if string parsing is the best way to achieve this. It shouldn't be too difficult because [ can only appear once anyway, so finding the corresponding ] is easy. But it could get stupid even without it: "aa{sa{i[ObjectDescription]}}".

Finally, if it's used only for naming *structs*, we could reuse the '(' syntax, like "(:ObjectDescription)".

Is compatibility with AllJoyn something we'd like? Note how they've extended the payload protocol already and we've added incompatible flags.
Comment 3 Simon McVittie 2016-02-02 14:05:52 UTC
(In reply to Thiago Macieira from comment #2)
> I'd require the type to remain as-is, with the current
> signature, for backwards compatibility.

Yes. Extensions should not break compatibility.

> Is compatibility with AllJoyn something we'd like? Note how they've extended
> the payload protocol already and we've added incompatible flags.

If they've effectively already forked the D-Bus specification, then I'm not particularly interested in avoiding further incompatibility.
Comment 4 Philip Withnall 2016-10-01 16:55:14 UTC
There are three new features they add to the introspection format on that wiki page:
 • Human readable <description>s for each element
 • Signal type specification — this seems to relate to some extension of theirs to the D-Bus protocol? (So I’ve ignored it.)
 • Named types

---

Human readable <descriptions>: This is basically bug #88997. I’ve proposed a solution for it in bug #98006, adding documentation as Markdown annotations in the introspection data.

---

Named types: I suggest we do something similar to above for named types: expose them as annotations in the introspection data. We can’t add them to the inline type information without extending the definition of D-Bus signatures, which would be monumentally backwards incompatible. Named types are not adding new data to the type, merely metadata, so it makes sense for them to be specified as annotations.

How about having an org.freedesktop.DBus.Introspection2.Types annotation, whose value has type a{s(sv)}; and an org.freedesktop.DBus.Introspection2.Type annotation, whose value has type s.

o.f.D.I2.Type must only be used to annotate arguments or properties, and its value must be the name of a custom type which was described in an o.f.D.I2.Types annotation on that argument or property, or higher up the introspection tree.

o.f.D.I2.Types could be annotated anywhere on the introspection tree, and the types defined in it would be scoped for that node and all its descendents in the tree. Shadowing a type from higher in the tree would be prohibited. Type definitions would otherwise be cumulative (i.e. the types available on a leaf node in the tree are the union of all the types defined on that leaf node and all its ancestors). In a more readable format, its type would be:

  dictionary
    {
      string name (this is the custom name for the type; it must use camel-case)
      struct
        {
          string type (see below)
          variant child_types
        }
    }

The custom type name must use camel-case, in order to be distinguishable from a D-Bus type signature.

The type string must either be:
 • a basic D-Bus type signature; or
 • a container D-Bus type signature, which must be consistent with the type information in child_types; or
 • one of the custom type names defined in the top-level array.

If a custom type’s type string, or one of the type strings of its child_types (recursively) is equal to the name of the custom type, it is a recursive type. In that case, the type string resolves to ‘v’.

In all cases, each custom type will be resolvable to a valid, definite D-Bus type signature.

The type of child_types depends on the type string:
 • e: ((ssv), (ssv))
 • r: a(ssv)
 • a: (ssv)
 • v: ()
 • any basic type: ()
 • custom type name: ()

All of the (ssv) types above contain nested type information with the same semantics as above. i.e. A type string which declares a dictionary (‘e’) has a tuple of two child_types: one for its key, and one for its value, both with an additional string giving a field name for the key or value. A type string which declares an array has exactly one child_type, with an additional string giving a field name for the element. Basic and custom types need no child_type information. A type string which declares a tuple has an array of zero or more child_types, each with an additional string giving the field name.

To take the examples from the AllJoyn page:

  <struct name="Inner">
    <field name="first" type="i"/>
    <field namd="second" type="i"/>
  </struct>
  <struct name="Outer">
    <field name="number" type="i"/>
    <field name="path" type="o"/>
    <field name="description" type="s"/>
    <field name="nested" type="[Inner]"/>
  </struct>
  <dict name="StringToInts">
    <key type="s"/>
    <value type="[Inner]"/>
  </dict>

they would be represented as (using GVariant text format):

  {
    'Inner': ('r',
      <[
        ('first', 'i', <()>),
        ('second', 'i', <()>),
      ]>),
    'Outer': ('r',
      <[
        ('number', 'i', <()>),
        ('path', 'o', <()>),
        ('description', 's', <()>),
        ('nested', 'Inner', <()>),
      ]>),
    'StringToInts': ('e',
      <(
        ('name', 's', <()>),
        ('cached_int_values', 'Inner', <()>),
      )>),
  }
  
Something with nested types, such as the out argument from o.f.D.ObjectManager.GetManagedObjects, might be represented as:

  {
    'Objects': ('e',
      <(
        ('object_path', 'o', <()>),
        ('interfaces', 'e', <(
          ('interface_name', 's', <()>),
          ('properties', 'e', <(
            ('property_name', 's', <()>),
            ('value', 'v', <()>),
          )>),
        )>),
      )>),
  }

Alternatively this could be split up into several custom types:

  {
    'Properties': ('e',
      <(
        ('property_name', 's', <()>),
        ('value', 'v', <()>),
      )>),
    'Interfaces': ('e',
      <(
        ('interface_name', 's', <()>),
        ('properties', 'Properties', <()>),
      )>),
    'Objects': ('e',
      <(
        ('object_path', 'o', <()>),
        ('interfaces', 'Interfaces', <()>),
      )>),
  }

Note that I don’t expect these type annotations to be hand written when exposed as introspection data via the o.f.D.I2.Introspect() method. That would be very error prone, and I don’t want consumers of the data to have to validate its consistency (for example, the consistency of parent types with their child types) when it is queried.

Overall, this is a fairly complex data structure, and asking a human to write it (so that code can be generated from it), is doomed to failure. I think it should be useful as an interchange format: as annotations on the results from a call to o.f.D.I2.Introspect(). However, it is not suitable as an input format for humans to write in the first place. Currently, I have no suggestions for that. I’m leaning towards suggesting that D-Bus interfaces are defined in code, and the introspection output is generated from that — rather than the existing prevalent model where they’re defined in introspection XML and a lot of stub code is generated from that.

This comment has gotten long enough. I’ll shut up now.

---

For reference, the objectives I was considering when thinking about this were:
 • Allow code generation
 • Allow types to be represented in debugging tools
 • Minimise duplication of data/signatures
 • Allow nested named types; maybe recursion?
 • Do not require backwards-incompatible changes to D-Bus or its type system
Comment 5 GitLab Migration User 2018-10-12 21:26:15 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/dbus/dbus/issues/141.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.