-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow defining element attributes via nested structures #9
Comments
There's more code duplication than I'm comfortable with in there, but I don't really see a way out of it - see thunderbird/xml-struct-rs#9 which describes the issue in more details.
I agree that what we have right now doesn't feel great or behave very intuitively. This behavior was an intentional decision so that we behave consistently for all tuples. If you declared That said, we currently have no way to treat a single-element tuple as a newtype, and that comes up much more frequently than I expect multi-element tuple variants to appear. I agree that we should solve this problem, as it doesn't match intuition and it makes it impossible to use a common Rust pattern. Suggestions welcome. |
Current behaviorThe primary pattern we use at present deals with struct Foo {
field: String,
other_field: String,
} In this case, the name of each field is used as the basis for the name of an XML element which encloses the contents of the field. For example, the following Rust value would be serialized as the subsequent XML: let foo = Foo {
field: String::from("some text"),
other_field: String::from("other text"),
};
foo.serialize_as_element(&mut writer, "Foo")?; <Foo>
<Field>some text</Field>
<OtherField>other text</OtherField>
</Foo> It is possible to declare that certain fields should be serialized as attributes on the enclosing element: struct Bar {
field: String,
#[xml_struct(attribute)]
other_field: String,
}
let bar = Bar {
field: String::from("some text"),
other_field: String::from("other text"),
};
bar.serialize_as_element(&mut writer, "Bar")?; <Bar OtherField="other text">
<Field>some text</Field>
</Bar> When a struct's fields are not named, we do not enclose the contents of those fields in XML elements: struct Baz(String, String);
let baz = Baz(String::from("some text"), String::from("other text"));
baz.serialize_as_element(&mut writer, "Baz")?; <Baz>some textother text</Baz> ProblemThe newtype pattern, wherein a type is enclosed in a struct with a single unnamed field in order to give the resulting type special behavior, is common in Rust and would be particularly useful for us in reusing structures which appear in enums. This generally works as expected when the enclosed type does not include any attribute fields. However, if a struct with attribute fields is enclosed in a tuple, its attribute fields are ignored. The field does not have its own enclosing element, and attempting to resolve attribute fields between multiple types could create conflicts or runtime errors. In the end, the combination of these behaviors creates a conflict of intuition, in which attempting to newtype a single struct with attribute fields causes those fields to be silently ignored, whereas we might generally expect them to be included in the surrounding element. Unfortunately, a derive macro cannot reliably introspect the types of fields, so there is no plausible means of allowing attribute fields on a single-element tuple but giving a compile-time error when they are used with multi-element tuples. |
There's more code duplication than I'm comfortable with in there, but I don't really see a way out of it - see thunderbird/xml-struct-rs#9 which describes the issue in more details. I have also made `message_disposition` not an `Option`, since as far as I'm aware this is a required field.
Consider:
MyEnum::Foo{..}
serializes into something like<someTagName AField="..." AnotherField="..." />
.Now consider that we want to extract
MyEnum::Foo
's inner structure into astruct
so it can be used directly by something else:Now
MyEnum::Foo(..)
serializes into something like<someTagName />
.A concrete example can be found in ews-rs.
PathToElement
is used to specify the identifier to a property to e.g. request from the EWS server. One of its variants isExtendedFieldURI
, which represents the identifier to an extended MAPI property.However, EWS also defines the
ExtendedProperty
element, which specifically expects anExtendedFieldURI
child element. In order to define this child element in Rust, without breaking the existing consumers ofPathToElement
, I can only see two non-ideal solutions:PathToElement::ExtendedFieldURI
into an independent struct, orExtendedProperty
definition specifyPathToElement
as the type for itsExtendedFieldURI
child element, which would also allow any other of its variants to be used, contrary to the specificationThe text was updated successfully, but these errors were encountered: