http/headers.bend source
http/headers.bend on the hub · documented module
import Baseimport ./text.bend as T# header fields in the order they came (RFC 9110 §5); a name may repeat,# and names compare ignoring casetype Header is Data: Header{name: String, value: String}def Headers() -> Type: List<&2, Header># headers' own compare: http1 calls T.same_ci with literals, which makes# it the owner of what it reads; a name used for every header would then# be shareddef name_eq(a: String, b: String, ok: Bool) -> Bool: match a b: case SNil{} SNil{}: ok case SCon{Chr{+x}, at} SCon{Chr{+y}, bt}: name_eq(at, bt, Bool.and(ok, T.fold.eq(x, y))) case _ _: False{}def keep(hit: Bool, v: String, found: Maybe<&2, String>) -> Maybe<&2, String>: match hit found: case True{} None{}: Some{v} case _ other: otherdef get.go(hs: List<&2, Header>, +name: String, found: Maybe<&2, String>) -> Maybe<&2, String>: match hs: case Nil{}: found case Con{Header{n, v}, t}: get.go(t, name, keep(name_eq(n, name, True{}), v, found))# the first value of a headerdef get(hs: List<&2, Header>, +name: String) -> Maybe<&2, String>: get.go(hs, name, None{})def all.add(hit: Bool, v: String, acc: List<&2, String>) -> List<&2, String>: match hit: case True{}: Con{v, acc} case False{}: accdef all.go(hs: List<&2, Header>, +name: String, acc: List<&2, String>) -> List<&2, String>: match hs: case Nil{}: List.reverse(&2, String, acc) case Con{Header{n, v}, t}: all.go(t, name, all.add(name_eq(n, name, True{}), v, acc))# every value of a header, in orderdef all(hs: List<&2, Header>, +name: String) -> List<&2, String>: all.go(hs, name, [])def drop.keep(hit: Bool, h: Header, acc: List<&2, Header>) -> List<&2, Header>: match hit: case True{}: acc case False{}: Con{h, acc}def drop.go(hs: List<&2, Header>, +name: String, acc: List<&2, Header>) -> List<&2, Header>: match hs: case Nil{}: List.reverse(&2, Header, acc) case Con{Header{+n, v}, t}: drop.go(t, name, drop.keep(name_eq(n, name, True{}), Header{n, v}, acc))# every header but those named namedef remove(hs: List<&2, Header>, +name: String) -> List<&2, Header>: drop.go(hs, name, [])# one more header, after the othersdef add(hs: List<&2, Header>, name: String, value: String) -> List<&2, Header>: List.append(&2, Header, hs, [Header{name, value}])# the header set to one value, replacing any othersdef set(hs: List<&2, Header>, +name: String, value: String) -> List<&2, Header>: add(remove(hs, name), name, value)