-
-
Save puckipedia/7c8ecbb391c397dbdaeb88a781fac447 to your computer and use it in GitHub Desktop.
quantum nix 2.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
with builtins; let | |
storePathHash = name: contents: hashString "sha256" "text:sha256:${hashString "sha256" contents}:/nix/store:${name}"; | |
hexToDecimal = hex: assert ((stringLength hex) / 2) * 2 == (stringLength hex); | |
let | |
nibble = w: if w == "0" then 0 | |
else if w == "1" then 1 | |
else if w == "2" then 2 | |
else if w == "3" then 3 | |
else if w == "4" then 4 | |
else if w == "5" then 5 | |
else if w == "6" then 6 | |
else if w == "7" then 7 | |
else if w == "8" then 8 | |
else if w == "9" then 9 | |
else if w == "a" then 10 | |
else if w == "b" then 11 | |
else if w == "c" then 12 | |
else if w == "d" then 13 | |
else if w == "e" then 14 | |
else if w == "f" then 15 | |
else -1; | |
byte = w: (nibble (substring 0 1 w)) * 16 + (nibble (substring 1 1 w)); | |
in | |
genList (a: byte (substring (a * 2) 2 hex)) ((stringLength hex) / 2); | |
shiftLeft = i: value: if i == 0 then value else (shiftLeft (i - 1) (value * 2)); | |
shiftRight = i: value: if i == 0 then value else (shiftRight (i - 1) (value / 2)); | |
decimalToBase32 = val: let | |
decimalToBase32Byte = i: let | |
offsetBits = i * 5; | |
byteIndex = (offsetBits / 8); | |
offset = offsetBits - (byteIndex * 8); | |
firstByte = shiftRight offset (elemAt val byteIndex); | |
secondByte = shiftLeft (8 - offset) | |
(if byteIndex >= (length val) - 1 then 0 else (elemAt val (byteIndex + 1))); | |
value = bitAnd 31 (bitOr firstByte secondByte); | |
in substring value 1 "0123456789abcdfghijklmnpqrsvwxyz"; | |
len = ((length val) * 8 - 1) / 5 + 1; | |
chars = genList (a: decimalToBase32Byte (len - 1 - a)) len; | |
in concatStringsSep "" chars; | |
compress = outLength: hash: | |
let | |
hashLen = (length hash); | |
forByte = i: | |
let | |
count = ((hashLen - i + outLength - 1) / outLength); | |
toXor = genList (j: elemAt hash (i + (outLength * j))) count; | |
in | |
foldl' bitXor 0 toXor; | |
in | |
genList forByte outLength; | |
in | |
name: contents: | |
let | |
hash = storePathHash name contents; | |
base32 = decimalToBase32 (compress 20 (hexToDecimal hash)); | |
in | |
"/nix/store/${base32}-${name}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
with builtins; let | |
filePath = import ./hash.nix; | |
availableFuseIndex = i: | |
let | |
hash = filePath "quantum-fuse" "root-${toString i}"; | |
in | |
if pathExists hash then (availableFuseIndex (i + 1)) else seq (toFile "quantum-fuse" "root-${toString i}") i; | |
fuseExists = fuse: index: pathExists (filePath "quantum-fuse" "chain-${toString fuse}-${toString index}"); | |
writeFuse = fuse: index: seq (toFile "quantum-fuse" "chain-${toString fuse}-${toString index}") null; | |
in rec { | |
# A fuse. Like a fuse, it can be blown exactly once. | |
fuse = value: | |
let | |
fuseIndex = availableFuseIndex 0; | |
in | |
{ | |
isBlown = _: fuseExists fuseIndex 0; | |
blowFuse = _: deepSeq (writeFuse fuseIndex 0) value; | |
}; | |
# A breaker, which can be set, reset, and flipped at will. | |
breaker = _: | |
let | |
fuseIndex = availableFuseIndex 0; | |
unblownIndex = val: if fuseExists fuseIndex val then unblownIndex (val + 1) else val; | |
in | |
rec { | |
getState = _: let index = unblownIndex 0; in (index / 2) * 2 == index; | |
flip = _: let index = unblownIndex 0; in deepSeq (writeFuse fuseIndex index) ((index / 2) * 2 == index); | |
setState = state: if (getState null) != state then flip null else state; | |
flipCount = _: unblownIndex 0; | |
}; | |
# Uses 64 breakers to store a single (positive, so actually 63 bit) integer. | |
quantumNumber = initial: | |
let | |
breakers = genList breaker 64; | |
findBit = num: n: if n == 0 then (bitAnd 1 num) == 1 else (findBit (num / 2) (n - 1)); | |
toBits = num: assert isInt num && num >= 0; genList (a: findBit num (63 - a)) 64; | |
fromBits = bits: foldl' (a: b: a * 2 + (if b then 1 else 0)) 0 bits; | |
flipBreakers = num: | |
let | |
bits = toBits num; | |
processed = toJSON (genList (n: (elemAt breakers n).setState (elemAt bits n)) 64); | |
in | |
seq processed null; | |
checkBreakers = _: fromBits (map (a: a.getState null) breakers); | |
in | |
seq (flipBreakers initial) { | |
setValue = flipBreakers; | |
getValue = checkBreakers; | |
}; | |
# Builds on top of the fuse to create a `once` -- the first time the resulting lambda is called, it will call the first argument. | |
# Every other time it calls the second one. | |
once = first: other: let | |
ownFuse = (fuse 0); | |
in value: | |
if ownFuse.isBlown null then | |
(other value) | |
else | |
seq (ownFuse.blowFuse null) (first value); | |
# Returns a lambda that increments a number every time it is called. | |
counter = start: let ownBreaker = (breaker null); in _: seq (ownBreaker.flip null) (ownBreaker.flipCount null) + start; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment