Skip to content

vitaminc-aead-value: a binding cannot name a value's kind without a value, so consumers copy the FfiValue tag table #365

Description

@coderdan

Background

vitaminc-aead-value is the crate a language binding uses to hand Vitamin C a value it cannot type at compile time. FfiValue is that value: a tagged enum (Bool, Int32, Int64, UInt32, UInt64, Float32, Float64, String, Bytes, Array, Object, plus Null, Undefined and Passthrough), and tags.rs holds the one-byte tag each variant is encoded with. The crate exists for this interop and nothing else.

Problem

A binding often needs to talk about the type of a value without having a value in hand: a plan that says "the age field is a uint64", a check that a value a host sent is the type the plan declared, a wire name for each type. vitaminc-aead-value offers no way to say that. There is no enum of kinds, no kind() on FfiValue, no mapping from a kind to its tag bytes, and no names.

Because of that, a consumer had to build its own. cipherstash/stack#1069 added an eleven-variant FieldType enum to stack-encrypt that mirrors FfiValue's variants, with tables mapping each variant to the constants in tags.rs (tags()), from a value to its variant (of()), and to wire names (name(), parse()). That is a second copy of this crate's type table, in another repository. It has to be kept in step by hand, and a variant added here is a silent gap there until someone notices.

Proposal

  1. Add ValueKind, an enum with one variant per typed FfiValue variant (Bool … Object), Copy/Eq/Hash/Debug/Display.
  2. FfiValue::kind(&self) -> Option<ValueKind>. Null, Undefined and Passthrough have no kind: the first two carry only one value each, and Passthrough is a transport choice whose inner value has its own kind.
  3. On ValueKind: ALL, name() and FromStr using the lowercase names already on the wire in the consumer (bool, int32, int64, uint32, uint64, float32, float64, string, bytes, array, object), tags() mapping back to the tags.rs constants, and holds(&FfiValue).
  4. Make FfiValue::kind an exhaustive match with no wildcard, so adding an FfiValue variant fails to compile until it is given a kind, and test that tags() partitions the tag table exactly.
  5. No numeric coercion and no index-admission rules: those are the consumer's.

Ship it in a 0.5.x release so the consumer can delete its copy and depend on this one.

Relationship to other work

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Vitamin CenhancementNew feature or requestrustPull requests that update Rust code

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions