der: add `IsConstructed` trait, impl'ed on any `FixedTag`
Closes #1741
This PR drops the need to implement Tagged on all structs that are IMPLICIT.
For example CHOICE does not implement FixedTag, but is always constructed.
This doesn't seem to do a whole lot as-is. What else are you planning on impl'ing IsConstructed on?
On trait Choice and my weird little edge case where derive(Choice) needed Tagged on something that wasn't.
If I remember correctly, the edge case is here: https://github.com/monai/node-passport/blob/master/lib/pkcs15/cryptographic_information_framework.asn1#L181
So it's a CHOICE with [0] CHOICE inside for ObjectValue {RSAPublicKeyChoice}
You should try to add it there, as I think for what you’re proposing the blanket impls(?) would conflict
It will take me some time to recreate the Tagged IMPLICIT bug with CHOICE inside [0] CHOICE :)
I give up. It's pretty much impossible to implement this case in current der, without splitting EXPLICIT and IMPLICIT encoders.
#[derive(Choice)]
pub enum ObjectValue<T>
where
for<'a> T: /* what to put here ? */,
{
Indirect(Path),
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
Direct(T),
}
[Spoiler] error[E0277]
error[E0277]: the trait bound `RSAPublicKeyChoice: FixedTag` is not satisfied
--> der/tests/derive.rs:261:52
|
261 | let object_value = ObjectValue::Direct(rsa_choice);
| ------------------- ^^^^^^^^^^ the trait `der::Sequence<'_>` is not implemented for `RSAPublicKeyChoice`
| |
| required by a bound introduced by this call
|
= note: required for `RSAPublicKeyChoice` to implement `FixedTag`
note: required by a bound in `ObjectValue::Direct`
--> der/tests/derive.rs:220:78
|
220 | for<'a> T: Encode + Decode<'a> + EncodeValue + DecodeValue<'a> + FixedTag,
| ^^^^^^^^ required by this bound in `ObjectValue::Direct`
...
225 | Direct(T),
| ------ required by a bound in this tuple variant
So ObjectValue::Direct should be bound:
- only by
EncodeValue + DecodeValue<'a> + IsConstructed, - but now
Encode + Decode<'a> + EncodeValue + DecodeValue<'a> + FixedTagis required.
Tagged and FixedTag traits are forced elsewere in the crate by ContextSpecific wrapper.
Btw CHOICE inside CHOICE isn't a problem. Such case can be simplified by hand.
/// ```asn1
/// ReferencedValue {Type} ::= CHOICE {
/// path Path,
/// url URL
/// }
/// URL ::= CHOICE {
/// url CHOICE {
/// printable PrintableString,
/// ia5 IA5String
/// },
/// urlWithDigest [3] SEQUENCE {
/// url IA5String,
/// digest DigestInfoWithDefault
/// }
/// }
/// ```
#[derive(Choice, Clone, Debug, Eq, PartialEq)]
#[tag_mode = "IMPLICIT"]
pub enum ReferencedValue {
Path(Path),
PrintableStringUrl(PrintableString),
Ia5StringUrl(Ia5String),
#[asn1(context_specific = "3")]
UrlWithDigest(()),
}
Nice. IsConstructed trait actually found a bug by itself.
NegHints ::= SEQUENCE {
hintName[0] GeneralString OPTIONAL,
AnyRef can be primitive or constructed, but GeneralString is strictly primitive.