You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 909b02a
Browse filesBrowse the repository at this point in the historyBrowse files
.encrypt_index::<String>("email", (Equality, Match::default())) // by name, through Field<String>
295
-
.encrypt_index(("email", |u:&User|&u.email), (Equality, Match::default())) // picker: the type is inferred
299
+
.encrypt_index(pick("email", |u:&User|&u.email), (Equality, Match::default())) // picker: the type is inferred
296
300
```
297
301
298
302
A bare name is looked up through the value's `Field<F>` impl, which is what a
299
303
dynamic value (`FfiValue`) provides. The picker reads the field directly and
300
304
needs no turbofish. The derive emits the picker form; bindings use names. The
301
305
picker is Rust-only.
302
306
307
+
Two spellings follow from how Rust infers types:
308
+
309
+
- A closure picker is written `pick("email", |u: &User| &u.email)`, not as a
310
+
bare tuple `("email", |u| &u.email)`, because Rust infers no higher-ranked
311
+
closure signature inside a tuple. A bare tuple holding a function item or
312
+
function pointer, `("email", email_fn)`, works as well.
313
+
- The field form of `encrypt_into` takes two type arguments, `::<T, _>(field)`
314
+
(the field's type is inferred), because Rust has no partial turbofish. The
315
+
one-value form takes one: `Plan::value::<S>().encrypt_into::<(A, B)>()`.
316
+
317
+
`EncryptFrom::indexes() -> Vec<IndexSpec>` is a defaulted method (empty unless
318
+
overridden) with which a typed target says which queries it answers. A typed
319
+
field whose target declares no indexes answers no queries; a query for anything
320
+
else is refused. Each term type names its own index, `Encrypted<Terms>` names
321
+
its set, and a tuple concatenates.
322
+
323
+
The built plan's accessors: `Plan::field_plans()` returns the field
324
+
descriptions (`Plan::fields()` is the start, so it cannot be the accessor);
325
+
`Plan::label()` and `FieldPlan::label()` return `Option<&Label>` (there is no
326
+
label until the call supplies the context); `Plan::context_field()` returns
327
+
`Option<&str>`.
328
+
303
329
### What `passthrough` means
304
330
305
331
Exactly what a passthrough leaf means in the Cipher today: the value is
@@ -317,14 +343,15 @@ this on the method.
317
343
|`Plan::value::<S>()`, `Plan::fields()`, `.context(c)`| the `NonEmpty<impl IntoContext>` handed to `under`| with `fields()`, each field gets `Label::new([context, identity])`|
318
344
|`with(idx)` / `encrypt_index(name, idx)`|`indexed::<S>(idx)`: `ciphertext().accepting::<CallerContext>().zip(..)…` then `map` into `Encrypted<Terms>`| each `Index<S>` returns its term operation; the tuple folds with `zip`|
319
345
|`encrypt_into::<T>(name)`, and the one-value form |`<T as EncryptFrom<F>>::encryption().under(label)`| the target's own description; no builder work |
346
+
|`EncryptFrom::indexes()` on a typed field | the indexes a query against that field may name | defaulted to empty: a typed field whose target declares none answers no queries (`IndexNotDeclared`) |
320
347
|`with(idx)` as `encrypt_into::<Encrypted<Terms>>`|`Encrypted<Terms>: EncryptFrom<S>`, whose `encryption()` is `indexed()`| both spellings lower to the same `indexed()`; a standing byte-identity test covers every index combination |
|`index(name, idx)`| the index operations alone, zipped, no `ciphertext()`|`Json` is one such operation; it mints one document key and seals every entry under it, a **new core operation** (one generate request, a fulfilment that seals N entries with selector-derived nonces) |
323
350
|`passthrough(name)`|`passthrough::<S>()` (#1069) | build is `Pending::ready(cipher, Ok(source))`, ignores the context |
324
351
|`context_field(name)`|`passthrough()` for that field; its value is the context every other field runs `under`| on open, the field's value is the `ExpectedContext` each field is opened under, so a record whose context field was changed in storage does not open |
325
352
|`fields()`, a field by name |`project_by` (crate-internal) through the value's `Field<F>`, `.under(label)`, `zip` across fields, `map` into the record | the path a dynamic value (`FfiValue`) takes |
326
-
|`fields()`, a field by picker `(name, accessor)`|`project(accessor)`| the derive's `struct = ..` mode today; borrowed-only |
327
-
|`build()`| a reusable recipe that produces a fresh `Encryption` per run | whole-plan rules checked here: names once, labels plain, no shared identity, passthrough not indexed, one context source, no empty label|
353
+
|`fields()`, a field by picker `pick(name, accessor)`|`project(accessor)`| the derive's `struct = ..` mode today; borrowed-only |
354
+
|`build()`| a reusable recipe that produces a fresh `Encryption` per run | whole-plan rules checked here: names once, labels plain, no shared identity, passthrough not indexed, one context source |
328
355
|`using(&plan)`|`KeysetCipher::run(encryption, source, ctx)` (#1068) of `Plan::encryption()`| execute-by-value; `encrypt_as` does this for a type through `T::encryption()`|
329
356
|`extend(parts)`| the runtime `DeclaredContext` value, `DeclaredContext::extend(own)`| not a combinator; it is the `ctx` argument |
330
357
|`keyset(..)`| the `KeysetCipher` passed to build; `Pending::scoped_to`||
@@ -546,7 +573,7 @@ are a bonus where the language has them.
546
573
547
574
**TypeScript already has a plan in another spelling.** `encryptedTable('users',
548
575
{ email: types.TextEq() })` is `Plan::context("users").fields()
549
-
.encrypt_into::<TextEq>("email")`, with the EQL domain as the field's target.
576
+
.encrypt_into::<TextEq, _>("email")`, with the EQL domain as the field's target.
550
577
Today that schema drives cipherstash-client through protect-ffi, a second
551
578
engine. The intended path is to retire protect-ffi and ship a new major of
552
579
`@cipherstash/stack` on stack-encrypt, with breaking changes; that release is
@@ -622,8 +649,8 @@ assembles EQL types from them:
622
649
623
650
```rust
624
651
letusers_plan=Plan::context("users").fields()
625
-
.encrypt_into::<TextEq>("email") // TextEq's own EncryptFrom decides the layout
626
-
.encrypt_into::<Json>("attrs") // EQL's JSON type frames the Json index's document
652
+
.encrypt_into::<TextEq, _>("email") // TextEq's own EncryptFrom decides the layout
653
+
.encrypt_into::<Json, _>("attrs") // EQL's JSON type frames the Json index's document
0 commit comments