src/metadata.bend

bendonnect-rpc@0.1.0.0 · 64 lines · 12 definitions

1# Header / trailer metadata helpers. Pure.
2# Metadata maps are Map<&2, List<&2, String>> with lowercase keys.
3import Base
4
5def trailer_prefix() -> String:
6  "trailer-"
7
8def trailers_to_headers.go(xs: List<&2, Sigma<&2, &2, String, _ => List<&2, String>>>, acc: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>:
9  match xs:
10    case Nil{}:
11      acc
12    case Con{Tuple{k, v}, rest}:
13      trailers_to_headers.go(rest, Map.set(&2, List<&2, String>, acc, String.append(trailer_prefix(), k), v))
14
15# Every key gets the "trailer-" prefix (unary responses carry trailers as headers).
16def trailers_to_headers(m: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>:
17  trailers_to_headers.go(Map.to_list(&2, List<&2, String>, m), Map.new(&2, List<&2, String>))
18
19# Adds k (with prefix stripped when want) when its prefix status equals want.
20def bool_eq(a: Bool, +b: Bool) -> Bool:
21  Bool.pick(Bool, a, b, Bool.not(b))
22
23def split.add(take: Bool, +want: Bool, +k: String, v: List<&2, String>, acc: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>:
24  match take:
25    case False{}:
26      acc
27    case True{}:
28      Map.set(&2, List<&2, String>, acc, Bool.pick(String, want, String.drop(k, 8n), k), v)
29
30def split.go(xs: List<&2, Sigma<&2, &2, String, _ => List<&2, String>>>, +want: Bool, acc: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>:
31  match xs:
32    case Nil{}:
33      acc
34    case Con{Tuple{+k, v}, rest}:
35      split.go(rest, want, split.add(bool_eq(String.starts_with(k, trailer_prefix()), want), want, k, v, acc))
36
37# (non-trailer headers, trailers with the "trailer-" prefix stripped)
38def split_trailers(h: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>> & Map<&2, List<&2, String>>:
39  +l = Map.to_list(&2, List<&2, String>, h)
40  (split.go(l, False{}, Map.new(&2, List<&2, String>)), split.go(l, True{}, Map.new(&2, List<&2, String>)))
41
42# Keys starting with "connect-" belong to the protocol.
43def is_reserved(+key: String) -> Bool:
44  String.starts_with(key, "connect-")
45
46# Keys ending in "-bin" carry base64 values.
47def is_binary(+key: String) -> Bool:
48  String.ends_with(key, "-bin")
49
50def key_char(+c: U32) -> Bool:
51  Bool.or(Bool.and(U32.is_ge(c, 48), U32.is_le(c, 57)),
52  Bool.or(Bool.and(U32.is_ge(c, 97), U32.is_le(c, 122)),
53  Bool.or(U32.is_eq(c, 95), Bool.or(U32.is_eq(c, 46), U32.is_eq(c, 45)))))
54
55def key_chars(s: String) -> Bool:
56  match s:
57    case SNil{}:
58      True{}
59    case SCon{Chr{+c}, t}:
60      Bool.and(key_char(c), key_chars(t))
61
62# 1*[0-9a-z_.-]
63def valid_key(+key: String) -> Bool:
64  Bool.and(Bool.not(String.is_empty(key)), key_chars(key))