make nt.nix safer

This commit is contained in:
Emile Clark-Boman 2026-01-27 11:13:22 +10:00
parent 6545f6d916
commit e9496d1994

View file

@ -1,67 +1,80 @@
{this, ...}: let {this, ...}: let
inherit inherit
(builtins) (builtins)
all
attrNames attrNames
elem elem
isAttrs getAttr
isString isString
typeOf typeOf
; ;
inherit
(this.std)
contains
;
inherit
(this.maybe)
isSome
mapMaybe
;
inherit inherit
(this.trapdoor) (this.trapdoor)
mkTrapdoorKey mkTrapdoorKey
openTrapdoor openTrapdoor
; ;
in rec { in rec {
openNT = openTrapdoor ntTrapdoorKey;
# check if a value is an nt type/class # check if a value is an nt type/class
isNT = T: let isNT = T:
content = openTrapdoor ntTrapdoorKey T; openNT T
names = attrNames content; |> mapMaybe (content: attrNames content |> contains ["sig" "derive" "ops" "req"])
in |> isSome;
isAttrs content
&& all (name: elem name names) ["sig" "derive" "ops" "req"];
isNixClass = T: let isNTClass = T:
content = openTrapdoor ntTrapdoorKey T; openNT T
in |> mapMaybe (content: attrNames content == ["sig" "derive" "ops" "req"])
isAttrs content |> isSome;
&& attrNames content == ["sig" "derive" "ops" "req"];
isNixType = T: let isNTType = T:
content = openTrapdoor ntTrapdoorKey T; openNT T
in |> mapMaybe (content:
isAttrs content attrNames content
&& attrNames content == ["instance" "sig" "derive" "ops" "req"] == ["instance" "sig" "derive" "ops" "req"]
&& content.instance == false; && content.instance == false)
|> isSome;
isNixTypeInstance = T: let isNTInstance = T:
content = openTrapdoor ntTrapdoorKey T; openNT T
in |> mapMaybe (content:
isAttrs content attrNames content
&& attrNames content == ["instance" "sig" "derive" "ops" "req"] == ["instance" "sig" "derive" "ops" "req"]
&& content.instance == true; && content.instance == true)
|> isSome;
# check if a type/class implements a signature # XXX: TODO: Some of these functions are unsafe but aren't marked as unsafe
# NOTE: unsafe variant, use typeSig if you can't guarantee `isNT T` holds # XXX: TODO: because they WILL BE safe once I implement isomorphisms between types
impls' = type: T: elem (toTypeSig type) T.${ntTrapdoorKey}.derive; # XXX: TODO: especially implicit isomorphism from nix primitives to NT types
# NOTE safe variant, use impls' if you can guarantee `isNT T` holds impls = type: T:
impls = type: T: assert enfIsNT T "nt.impls"; impls' type T; assert enfIsNT T "nt.impls";
openNT T
|> mapMaybe (content: content.derive |> elem (toTypeSig type))
|> isSome;
# check if a type/class implements a signature is = type: T:
# NOTE: unsafe variant, use `is` if you can't guarantee `isNT T` holds assert enfIsNT T "nt.is";
is' = type: T: T.${ntTrapdoorKey}.sig == toTypeSig type; openNT T
|> mapMaybe (content: content.sig == toTypeSig type)
|> isSome;
# NOTE safe variant, use `is'` if you can guarantee `isNT T` holds typeSig = T:
is = type: T: assert enfIsNT T "nt.is"; is' type T; assert enfIsNT T "nt.typeSig";
openNT T
# NOTE: unsafe variant, use typeSig if you can't guarantee `isNT T` holds |> mapMaybe (getAttr "sig")
typeSig' = T: T.${ntTrapdoorKey}.sig; |> isSome;
# # NOTE: safe variant, use typeSig' if you can guarantee `isNT T` holds
typeSig = T: assert enfIsNT T "nt.typeSig"; typeSig' T;
toTypeSig = x: toTypeSig = x:
if isString x if isString x
@ -71,6 +84,7 @@ in rec {
# XXX: TODO: move ntTrapdoorKey to nt.nix # XXX: TODO: move ntTrapdoorKey to nt.nix
ntTrapdoorKey = mkTrapdoorKey "nt"; ntTrapdoorKey = mkTrapdoorKey "nt";
# TODO: rename enfIsType -> enfIsPrimitive
enfIsType = type: value: msg: let enfIsType = type: value: msg: let
got = typeOf value; got = typeOf value;
in in