@shd101wyy/yo 0.1.29 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/SKILL.md +3 -3
- package/.github/skills/yo-async-effects/async-effects-recipes.md +19 -11
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +33 -13
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +1 -1
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +59 -21
- package/README.md +4 -3
- package/out/cjs/index.cjs +771 -676
- package/out/cjs/yo-cli.cjs +1003 -898
- package/out/cjs/yo-lsp.cjs +834 -739
- package/out/esm/index.mjs +716 -621
- package/out/types/src/codegen/exprs/async.d.ts +2 -0
- package/out/types/src/codegen/exprs/await.d.ts +1 -0
- package/out/types/src/codegen/exprs/closures.d.ts +4 -0
- package/out/types/src/codegen/functions/context.d.ts +6 -0
- package/out/types/src/env.d.ts +2 -0
- package/out/types/src/evaluator/builtins/pragma.d.ts +9 -0
- package/out/types/src/evaluator/builtins/unsafe.d.ts +8 -0
- package/out/types/src/evaluator/context.d.ts +2 -0
- package/out/types/src/evaluator/index.d.ts +1 -1
- package/out/types/src/evaluator/memory-safety.d.ts +14 -0
- package/out/types/src/evaluator/types/flowability.d.ts +6 -0
- package/out/types/src/expr-traversal.d.ts +1 -0
- package/out/types/src/expr.d.ts +4 -1
- package/out/types/src/public-safe-report.d.ts +19 -0
- package/out/types/src/tests/comptime-ref-gate.test.d.ts +1 -0
- package/out/types/src/tests/pragma-validation.test.d.ts +1 -0
- package/out/types/src/tests/public-safe-report.test.d.ts +1 -0
- package/out/types/src/tests/type-representation-pointer.test.d.ts +1 -0
- package/out/types/src/tests/unsafe-gate.test.d.ts +1 -0
- package/out/types/src/tests/unsafe-report-classify.test.d.ts +1 -0
- package/out/types/src/types/definitions.d.ts +2 -0
- package/out/types/src/types/utils.d.ts +4 -0
- package/out/types/src/unsafe-report.d.ts +29 -0
- package/out/types/src/value.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/scripts/add-pragma-for-pointer-decls.ts +134 -0
- package/scripts/add-pragma.ts +58 -0
- package/scripts/migrate-amp-method-calls.ts +186 -0
- package/scripts/migrate-clone-calls.ts +93 -0
- package/scripts/migrate-get-unwrap.ts +166 -0
- package/scripts/migrate-index-patterns.ts +210 -0
- package/scripts/migrate-index-trait.ts +142 -0
- package/scripts/migrate-iterator.ts +150 -0
- package/scripts/migrate-self-ptr.ts +220 -0
- package/scripts/migrate-skip-pragmas.ts +109 -0
- package/scripts/migrate-tostring.ts +134 -0
- package/scripts/trim-pragma.ts +130 -0
- package/scripts/wrap-extern-calls.ts +161 -0
- package/std/alg/hash.yo +3 -2
- package/std/allocator.yo +6 -5
- package/std/async.yo +2 -2
- package/std/collections/array_list.yo +59 -40
- package/std/collections/btree_map.yo +19 -18
- package/std/collections/deque.yo +9 -8
- package/std/collections/hash_map.yo +101 -13
- package/std/collections/hash_set.yo +5 -4
- package/std/collections/linked_list.yo +39 -4
- package/std/collections/ordered_map.yo +3 -3
- package/std/collections/priority_queue.yo +14 -13
- package/std/crypto/md5.yo +2 -1
- package/std/crypto/random.yo +16 -15
- package/std/crypto/sha256.yo +2 -1
- package/std/encoding/base64.yo +14 -14
- package/std/encoding/hex.yo +3 -3
- package/std/encoding/json.yo +59 -10
- package/std/encoding/punycode.yo +24 -23
- package/std/encoding/toml.yo +4 -3
- package/std/encoding/utf16.yo +2 -2
- package/std/env.yo +43 -28
- package/std/error.yo +6 -6
- package/std/fmt/display.yo +2 -2
- package/std/fmt/index.yo +6 -5
- package/std/fmt/to_string.yo +39 -38
- package/std/fmt/writer.yo +9 -8
- package/std/fs/dir.yo +34 -33
- package/std/fs/file.yo +52 -51
- package/std/fs/metadata.yo +10 -9
- package/std/fs/temp.yo +24 -13
- package/std/fs/walker.yo +10 -9
- package/std/gc.yo +1 -0
- package/std/glob.yo +7 -7
- package/std/http/client.yo +15 -14
- package/std/http/http.yo +6 -6
- package/std/http/index.yo +1 -1
- package/std/imm/list.yo +33 -0
- package/std/imm/map.yo +2 -1
- package/std/imm/set.yo +1 -0
- package/std/imm/sorted_map.yo +1 -0
- package/std/imm/sorted_set.yo +1 -0
- package/std/imm/string.yo +27 -23
- package/std/imm/vec.yo +18 -2
- package/std/io/reader.yo +2 -1
- package/std/io/writer.yo +3 -2
- package/std/libc/assert.yo +1 -0
- package/std/libc/ctype.yo +1 -0
- package/std/libc/dirent.yo +1 -0
- package/std/libc/errno.yo +1 -0
- package/std/libc/fcntl.yo +1 -0
- package/std/libc/float.yo +1 -0
- package/std/libc/limits.yo +1 -0
- package/std/libc/math.yo +1 -0
- package/std/libc/signal.yo +1 -0
- package/std/libc/stdatomic.yo +1 -0
- package/std/libc/stdint.yo +1 -0
- package/std/libc/stdio.yo +1 -0
- package/std/libc/stdlib.yo +1 -0
- package/std/libc/string.yo +1 -0
- package/std/libc/sys/stat.yo +1 -0
- package/std/libc/time.yo +1 -0
- package/std/libc/unistd.yo +1 -0
- package/std/libc/wctype.yo +1 -0
- package/std/libc/windows.yo +2 -0
- package/std/log.yo +7 -6
- package/std/net/addr.yo +5 -4
- package/std/net/dns.yo +7 -6
- package/std/net/errors.yo +8 -8
- package/std/net/tcp.yo +19 -18
- package/std/net/udp.yo +13 -12
- package/std/os/signal.yo +3 -3
- package/std/path.yo +1 -0
- package/std/prelude.yo +353 -182
- package/std/process/command.yo +40 -23
- package/std/process/index.yo +2 -1
- package/std/regex/compiler.yo +10 -9
- package/std/regex/index.yo +41 -41
- package/std/regex/match.yo +2 -2
- package/std/regex/parser.yo +21 -21
- package/std/regex/vm.yo +42 -41
- package/std/string/string.yo +95 -40
- package/std/string/string_builder.yo +9 -9
- package/std/string/unicode.yo +50 -49
- package/std/sync/channel.yo +2 -1
- package/std/sync/cond.yo +5 -4
- package/std/sync/mutex.yo +4 -3
- package/std/sys/advise.yo +1 -0
- package/std/sys/bufio/buf_reader.yo +17 -16
- package/std/sys/bufio/buf_writer.yo +10 -9
- package/std/sys/clock.yo +1 -0
- package/std/sys/copy.yo +1 -0
- package/std/sys/dir.yo +10 -9
- package/std/sys/dns.yo +6 -5
- package/std/sys/errors.yo +11 -11
- package/std/sys/events.yo +1 -0
- package/std/sys/externs.yo +38 -37
- package/std/sys/file.yo +17 -16
- package/std/sys/future.yo +4 -3
- package/std/sys/iov.yo +1 -0
- package/std/sys/mmap.yo +1 -0
- package/std/sys/path.yo +1 -0
- package/std/sys/perm.yo +2 -1
- package/std/sys/pipe.yo +1 -0
- package/std/sys/process.yo +5 -4
- package/std/sys/signal.yo +1 -0
- package/std/sys/socketpair.yo +1 -0
- package/std/sys/sockinfo.yo +1 -0
- package/std/sys/statfs.yo +2 -1
- package/std/sys/statx.yo +1 -0
- package/std/sys/sysinfo.yo +1 -0
- package/std/sys/tcp.yo +15 -14
- package/std/sys/temp.yo +1 -0
- package/std/sys/time.yo +2 -1
- package/std/sys/timer.yo +6 -6
- package/std/sys/tty.yo +2 -1
- package/std/sys/udp.yo +13 -12
- package/std/sys/unix.yo +12 -11
- package/std/testing/bench.yo +4 -3
- package/std/thread.yo +7 -6
- package/std/time/datetime.yo +18 -15
- package/std/time/duration.yo +11 -10
- package/std/time/instant.yo +4 -4
- package/std/time/sleep.yo +1 -0
- package/std/url/index.yo +3 -3
- package/std/worker.yo +4 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//! Hash map using SwissTable algorithm with SIMD-accelerated lookup.
|
|
2
|
+
pragma(Pragma.AllowUnsafe);
|
|
2
3
|
{ GlobalAllocator, AllocError } :: import("../allocator.yo");
|
|
3
4
|
{ malloc, calloc, realloc, free } :: GlobalAllocator;
|
|
4
5
|
/// Error variants for HashMap operations.
|
|
@@ -491,7 +492,7 @@ impl(
|
|
|
491
492
|
HashMapIter(K, V),
|
|
492
493
|
Iterator(
|
|
493
494
|
Item : Bucket(K, V),
|
|
494
|
-
next : (fn(self :
|
|
495
|
+
next : (fn(ref(self) : Self) -> Option(Bucket(K, V)))(
|
|
495
496
|
cond(
|
|
496
497
|
(self._map.capacity == usize(0)) =>.None,
|
|
497
498
|
true => {
|
|
@@ -537,7 +538,7 @@ impl(
|
|
|
537
538
|
HashMapIterPtr(K, V),
|
|
538
539
|
Iterator(
|
|
539
540
|
Item : *(Bucket(K, V)),
|
|
540
|
-
next : (fn(self :
|
|
541
|
+
next : (fn(ref(self) : Self) -> Option(*(Bucket(K, V))))(
|
|
541
542
|
cond(
|
|
542
543
|
(self._map.capacity == usize(0)) =>.None,
|
|
543
544
|
true => {
|
|
@@ -563,8 +564,12 @@ impl(
|
|
|
563
564
|
forall(K : Type, V : Type),
|
|
564
565
|
where(K <: (Eq(K), Hash)),
|
|
565
566
|
HashMap(K, V),
|
|
566
|
-
|
|
567
|
-
|
|
567
|
+
/// Pointer iterator — yields `*(Bucket(K, V))` for each occupied bucket.
|
|
568
|
+
/// Kept as a separate method (not `iter()`) so the Phase D for-macro's
|
|
569
|
+
/// `coll.iter()` call dispatches to the position-iter variant defined
|
|
570
|
+
/// later in the file, enabling `for(map, ref(b) => body)`.
|
|
571
|
+
iter_ptr : (fn(self : Self) -> HashMapIterPtr(K, V))(
|
|
572
|
+
HashMapIterPtr(K, V)(_map : self, _index : usize(0))
|
|
568
573
|
)
|
|
569
574
|
);
|
|
570
575
|
/**
|
|
@@ -581,7 +586,7 @@ impl(
|
|
|
581
586
|
HashMapKeys(K, V),
|
|
582
587
|
Iterator(
|
|
583
588
|
Item : K,
|
|
584
|
-
next : (fn(self :
|
|
589
|
+
next : (fn(ref(self) : Self) -> Option(K))(
|
|
585
590
|
match(
|
|
586
591
|
self._inner.next(),
|
|
587
592
|
.None =>.None,
|
|
@@ -612,7 +617,7 @@ impl(
|
|
|
612
617
|
HashMapValues(K, V),
|
|
613
618
|
Iterator(
|
|
614
619
|
Item : V,
|
|
615
|
-
next : (fn(self :
|
|
620
|
+
next : (fn(ref(self) : Self) -> Option(V))(
|
|
616
621
|
match(
|
|
617
622
|
self._inner.next(),
|
|
618
623
|
.None =>.None,
|
|
@@ -634,13 +639,13 @@ impl(
|
|
|
634
639
|
HashMap(K, V),
|
|
635
640
|
Index(K)(
|
|
636
641
|
Output : V,
|
|
637
|
-
index : (fn(self :
|
|
642
|
+
index : (fn(ref(self) : Self, idx : K, where(K <: (Eq(K), Hash))) -> *(Self.Output))({
|
|
638
643
|
hash := idx.hash();
|
|
639
|
-
bucket_opt := Self._find_bucket(self
|
|
644
|
+
bucket_opt := Self._find_bucket(self, idx, hash);
|
|
640
645
|
match(
|
|
641
646
|
bucket_opt,
|
|
642
647
|
.Some(i) => {
|
|
643
|
-
data_ptr := Self._data_ptr(self
|
|
648
|
+
data_ptr := Self._data_ptr(self);
|
|
644
649
|
&((data_ptr &+ i).*.value)
|
|
645
650
|
},
|
|
646
651
|
.None => panic("HashMap: key not found")
|
|
@@ -648,15 +653,93 @@ impl(
|
|
|
648
653
|
})
|
|
649
654
|
)
|
|
650
655
|
);
|
|
656
|
+
/// Position iterator for HashMap that walks occupied buckets and yields
|
|
657
|
+
/// their bucket indices. Pairs with the `Indexable(usize)` impl below to
|
|
658
|
+
/// make `for(map, ref(b) => body)` legal: `b` becomes a `ref(Bucket(K, V))`
|
|
659
|
+
/// and the loop body can destructure `b.key` / `b.value`.
|
|
660
|
+
HashMapPosIter :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
|
|
661
|
+
struct(
|
|
662
|
+
_map : HashMap(K, V),
|
|
663
|
+
_index : usize
|
|
664
|
+
)
|
|
665
|
+
);
|
|
666
|
+
impl(
|
|
667
|
+
forall(K : Type, V : Type),
|
|
668
|
+
where(K <: (Eq(K), Hash)),
|
|
669
|
+
HashMapPosIter(K, V),
|
|
670
|
+
Iterator(
|
|
671
|
+
Item : usize,
|
|
672
|
+
next : (fn(ref(self) : Self) -> Option(usize))(
|
|
673
|
+
cond(
|
|
674
|
+
(self._map.capacity == usize(0)) =>.None,
|
|
675
|
+
true => {
|
|
676
|
+
ctrl_ptr := self._map.ctrl.unwrap();
|
|
677
|
+
result := Option(usize).None;
|
|
678
|
+
while((self._index < self._map.capacity) && result.is_none(), self._index = (self._index + usize(1)), {
|
|
679
|
+
ctrl_byte := (ctrl_ptr &+ self._index).*;
|
|
680
|
+
cond(
|
|
681
|
+
((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
|
|
682
|
+
result =.Some(self._index);
|
|
683
|
+
},
|
|
684
|
+
true => ()
|
|
685
|
+
);
|
|
686
|
+
});
|
|
687
|
+
result
|
|
688
|
+
}
|
|
689
|
+
)
|
|
690
|
+
)
|
|
691
|
+
)
|
|
692
|
+
);
|
|
693
|
+
/// Indexable(usize) — projects an occupied bucket index back to a
|
|
694
|
+
/// `ref(Bucket(K, V))` so `for(map, ref(b) => ...)` works. The body of
|
|
695
|
+
/// `for` (Phase D) calls `coll.iter()` to obtain a position iter and
|
|
696
|
+
/// then `coll.project(pos)` for each yielded position. We override
|
|
697
|
+
/// `iter` for HashMap to return the position-iter rather than the
|
|
698
|
+
/// `*(Bucket)` iter — the for-macro only cares about which yields
|
|
699
|
+
/// positions consumable by `project`.
|
|
700
|
+
///
|
|
701
|
+
/// See plans/ITERATOR_REDESIGN.md Open Question 3. The choice here is
|
|
702
|
+
/// "projection-returns a single Bucket struct, user destructures
|
|
703
|
+
/// inside the loop" — chosen over the rejected `(ref(K), ref(V))`
|
|
704
|
+
/// tuple-of-inouts shape.
|
|
705
|
+
impl(
|
|
706
|
+
forall(K : Type, V : Type),
|
|
707
|
+
where(K <: (Eq(K), Hash)),
|
|
708
|
+
HashMap(K, V),
|
|
709
|
+
Indexable(usize)(
|
|
710
|
+
Element : Bucket(K, V),
|
|
711
|
+
project : (fn(ref(self) : Self, pos : usize) -> ref(Bucket(K, V)))(
|
|
712
|
+
cond(
|
|
713
|
+
(pos >= self.capacity) => panic("HashMap: project out of bounds"),
|
|
714
|
+
// SAFETY: cond above bounds `pos`; `_data_ptr` returns the
|
|
715
|
+
// start of the Rc-managed _data buffer, which is alive while
|
|
716
|
+
// `self` holds the Rc.
|
|
717
|
+
true => unsafe(Self._data_ptr(self) &+ pos)
|
|
718
|
+
)
|
|
719
|
+
)
|
|
720
|
+
)
|
|
721
|
+
);
|
|
722
|
+
/// Position-iter constructor for HashMap (paired with the Indexable
|
|
723
|
+
/// impl above): `iter()` yields each occupied bucket index, and the
|
|
724
|
+
/// for-macro then calls `coll.project(pos)` to materialize the
|
|
725
|
+
/// `ref(Bucket)` borrow for the body.
|
|
726
|
+
impl(
|
|
727
|
+
forall(K : Type, V : Type),
|
|
728
|
+
where(K <: (Eq(K), Hash)),
|
|
729
|
+
HashMap(K, V),
|
|
730
|
+
iter : (fn(self : Self) -> HashMapPosIter(K, V))(
|
|
731
|
+
HashMapPosIter(K, V)(_map : self, _index : usize(0))
|
|
732
|
+
)
|
|
733
|
+
);
|
|
651
734
|
/// Clone implementation for HashMap — deep-clones all key-value entries.
|
|
652
735
|
impl(
|
|
653
736
|
forall(K : Type, V : Type),
|
|
654
737
|
where(K <: (Clone, Eq(K), Hash), V <: Clone),
|
|
655
738
|
HashMap(K, V),
|
|
656
739
|
Clone(
|
|
657
|
-
clone : (fn(self :
|
|
740
|
+
clone : (fn(ref(self) : Self) -> Self)({
|
|
658
741
|
result := Self.new();
|
|
659
|
-
it := self.
|
|
742
|
+
it := self.iter_ptr();
|
|
660
743
|
running := true;
|
|
661
744
|
while(running, {
|
|
662
745
|
nxt := it.next();
|
|
@@ -666,8 +749,13 @@ impl(
|
|
|
666
749
|
running = false;
|
|
667
750
|
},
|
|
668
751
|
.Some(bucket_ptr) => {
|
|
669
|
-
|
|
670
|
-
|
|
752
|
+
// SAFETY: iter_ptr().next() returns .Some(p) only when p
|
|
753
|
+
// points at an occupied bucket within the Rc-managed
|
|
754
|
+
// _data buffer; the buffer is alive while `self` holds
|
|
755
|
+
// the Rc (we received `ref(self)` so the caller still
|
|
756
|
+
// owns it across this call).
|
|
757
|
+
k := unsafe(bucket_ptr.*.key.clone());
|
|
758
|
+
v := unsafe(bucket_ptr.*.value.clone());
|
|
671
759
|
result.set(k, v);
|
|
672
760
|
}
|
|
673
761
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//! Hash set using SwissTable algorithm with set-theoretic operations.
|
|
2
|
+
pragma(Pragma.AllowUnsafe);
|
|
2
3
|
{ GlobalAllocator, AllocError } :: import("../allocator.yo");
|
|
3
4
|
{ malloc, calloc, realloc, free } :: GlobalAllocator;
|
|
4
5
|
/// Error variants for HashSet operations.
|
|
@@ -688,7 +689,7 @@ impl(
|
|
|
688
689
|
HashSetIter(T),
|
|
689
690
|
Iterator(
|
|
690
691
|
Item : T,
|
|
691
|
-
next : (fn(self :
|
|
692
|
+
next : (fn(ref(self) : Self) -> Option(T))(
|
|
692
693
|
cond(
|
|
693
694
|
(self._set.capacity == usize(0)) =>.None,
|
|
694
695
|
true => {
|
|
@@ -734,7 +735,7 @@ impl(
|
|
|
734
735
|
HashSetIterPtr(T),
|
|
735
736
|
Iterator(
|
|
736
737
|
Item : *(T),
|
|
737
|
-
next : (fn(self :
|
|
738
|
+
next : (fn(ref(self) : Self) -> Option(*(T)))(
|
|
738
739
|
cond(
|
|
739
740
|
(self._set.capacity == usize(0)) =>.None,
|
|
740
741
|
true => {
|
|
@@ -760,8 +761,8 @@ impl(
|
|
|
760
761
|
forall(T : Type),
|
|
761
762
|
where(T <: (Eq(T), Hash)),
|
|
762
763
|
HashSet(T),
|
|
763
|
-
iter : (fn(self :
|
|
764
|
-
HashSetIterPtr(T)(_set : self
|
|
764
|
+
iter : (fn(self : Self) -> HashSetIterPtr(T))(
|
|
765
|
+
HashSetIterPtr(T)(_set : self, _index : usize(0))
|
|
765
766
|
)
|
|
766
767
|
);
|
|
767
768
|
export(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//! Doubly-linked list with O(1) push/pop at both ends.
|
|
2
2
|
/// Error variants for LinkedList operations.
|
|
3
|
+
pragma(Pragma.AllowUnsafe);
|
|
3
4
|
LinkedListError :: enum(
|
|
4
5
|
/// Index is out of bounds for the current length.
|
|
5
6
|
IndexOutOfBounds(index : usize, length : usize),
|
|
@@ -409,7 +410,7 @@ impl(
|
|
|
409
410
|
LinkedListIter(T),
|
|
410
411
|
Iterator(
|
|
411
412
|
Item : T,
|
|
412
|
-
next : (fn(self :
|
|
413
|
+
next : (fn(ref(self) : Self) -> Option(T))(
|
|
413
414
|
match(
|
|
414
415
|
self._current,
|
|
415
416
|
.None =>.None,
|
|
@@ -443,7 +444,7 @@ impl(
|
|
|
443
444
|
LinkedListIterPtr(T),
|
|
444
445
|
Iterator(
|
|
445
446
|
Item : *(T),
|
|
446
|
-
next : (fn(self :
|
|
447
|
+
next : (fn(ref(self) : Self) -> Option(*(T)))(
|
|
447
448
|
match(
|
|
448
449
|
self._current,
|
|
449
450
|
.None =>.None,
|
|
@@ -458,8 +459,42 @@ impl(
|
|
|
458
459
|
impl(
|
|
459
460
|
forall(T : Type),
|
|
460
461
|
LinkedList(T),
|
|
461
|
-
iter : (fn(self :
|
|
462
|
-
LinkedListIterPtr(T)(_current : self
|
|
462
|
+
iter : (fn(self : Self) -> LinkedListIterPtr(T))(
|
|
463
|
+
LinkedListIterPtr(T)(_current : self.head)
|
|
464
|
+
)
|
|
465
|
+
);
|
|
466
|
+
/// Index trait — `list(idx)` returns the element at `idx`. O(n) walk.
|
|
467
|
+
/// `&(node.value)` is a valid heap pointer while `self` keeps the
|
|
468
|
+
/// Rc chain alive — the dispatcher inlines and dereferences this
|
|
469
|
+
/// before any drop runs. Same pattern as `LinkedListIterPtr.next`.
|
|
470
|
+
impl(
|
|
471
|
+
forall(T : Type),
|
|
472
|
+
LinkedList(T),
|
|
473
|
+
Index(usize)(
|
|
474
|
+
Output : T,
|
|
475
|
+
index : (fn(ref(self) : Self, idx : usize) -> *(Self.Output))({
|
|
476
|
+
assert(idx < self.length, "LinkedList: index out of bounds");
|
|
477
|
+
(current : Option(Node(T))) = self.head;
|
|
478
|
+
i := usize(0);
|
|
479
|
+
while(runtime(true), {
|
|
480
|
+
match(
|
|
481
|
+
current,
|
|
482
|
+
.Some(node) => {
|
|
483
|
+
if(i == idx, {
|
|
484
|
+
// SAFETY: `node` is held in an Rc-managed chain rooted
|
|
485
|
+
// at `self.head`; while `self` is borrowed (ref(self))
|
|
486
|
+
// every node we've walked stays alive, so `&node.value`
|
|
487
|
+
// is a valid borrow into Rc storage.
|
|
488
|
+
return(unsafe(&(node.value)));
|
|
489
|
+
});
|
|
490
|
+
current = node.next;
|
|
491
|
+
i = (i + usize(1));
|
|
492
|
+
},
|
|
493
|
+
.None => panic("LinkedList: unreachable past length check")
|
|
494
|
+
);
|
|
495
|
+
});
|
|
496
|
+
panic("LinkedList: index loop exited without return")
|
|
497
|
+
})
|
|
463
498
|
)
|
|
464
499
|
);
|
|
465
500
|
export(
|
|
@@ -142,7 +142,7 @@ impl(
|
|
|
142
142
|
forall(K : Type, V : Type),
|
|
143
143
|
where(K <: (Eq(K), Hash)),
|
|
144
144
|
OrderedMapKeys(K, V),
|
|
145
|
-
next : (fn(self :
|
|
145
|
+
next : (fn(ref(self) : Self) -> Option(K))({
|
|
146
146
|
cond(
|
|
147
147
|
(self._index >= self._map._order.len()) => {
|
|
148
148
|
return(.None);
|
|
@@ -171,7 +171,7 @@ impl(
|
|
|
171
171
|
forall(K : Type, V : Type),
|
|
172
172
|
where(K <: (Eq(K), Hash)),
|
|
173
173
|
OrderedMapValues(K, V),
|
|
174
|
-
next : (fn(self :
|
|
174
|
+
next : (fn(ref(self) : Self) -> Option(V))({
|
|
175
175
|
cond(
|
|
176
176
|
(self._index >= self._map._order.len()) => {
|
|
177
177
|
return(.None);
|
|
@@ -219,7 +219,7 @@ impl(
|
|
|
219
219
|
forall(K : Type, V : Type),
|
|
220
220
|
where(K <: (Eq(K), Hash)),
|
|
221
221
|
OrderedMapIter(K, V),
|
|
222
|
-
next : (fn(self :
|
|
222
|
+
next : (fn(ref(self) : Self) -> Option(OrderedMapEntry(K, V)))({
|
|
223
223
|
cond(
|
|
224
224
|
(self._index >= self._map._order.len()) => {
|
|
225
225
|
return(.None);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
//! pq.push(3);
|
|
12
12
|
//! x := pq.pop().unwrap(); // 1
|
|
13
13
|
//! ```
|
|
14
|
+
pragma(Pragma.AllowUnsafe);
|
|
14
15
|
{ ArrayList } :: import("./array_list");
|
|
15
16
|
/// Min-heap backed by an ArrayList.
|
|
16
17
|
/// Elements are ordered ascending (smallest first). Negate keys for max-heap behavior.
|
|
@@ -48,8 +49,8 @@ impl(
|
|
|
48
49
|
i := (self._data.len() - usize(1));
|
|
49
50
|
while(i > usize(0), {
|
|
50
51
|
parent := ((i - usize(1)) / usize(2));
|
|
51
|
-
child_val := self._data
|
|
52
|
-
parent_val := self._data
|
|
52
|
+
child_val := self._data(i);
|
|
53
|
+
parent_val := self._data(parent);
|
|
53
54
|
cond(
|
|
54
55
|
(child_val < parent_val) => {
|
|
55
56
|
&(self._data(i)).* = parent_val;
|
|
@@ -68,8 +69,8 @@ impl(
|
|
|
68
69
|
cond(
|
|
69
70
|
(n == usize(0)) =>.None,
|
|
70
71
|
true => {
|
|
71
|
-
top := self._data
|
|
72
|
-
last := self._data
|
|
72
|
+
top := self._data(usize(0));
|
|
73
|
+
last := self._data(n - usize(1));
|
|
73
74
|
&(self._data(usize(0))).* = last;
|
|
74
75
|
self._data.pop();
|
|
75
76
|
// Sift down
|
|
@@ -80,13 +81,13 @@ impl(
|
|
|
80
81
|
smallest := i;
|
|
81
82
|
new_n := self._data.len();
|
|
82
83
|
cond(
|
|
83
|
-
((left < new_n) && (self._data
|
|
84
|
+
((left < new_n) && (self._data(left) < self._data(smallest))) => {
|
|
84
85
|
smallest = left;
|
|
85
86
|
},
|
|
86
87
|
true => ()
|
|
87
88
|
);
|
|
88
89
|
cond(
|
|
89
|
-
((right < new_n) && (self._data
|
|
90
|
+
((right < new_n) && (self._data(right) < self._data(smallest))) => {
|
|
90
91
|
smallest = right;
|
|
91
92
|
},
|
|
92
93
|
true => ()
|
|
@@ -96,8 +97,8 @@ impl(
|
|
|
96
97
|
break;
|
|
97
98
|
},
|
|
98
99
|
true => {
|
|
99
|
-
a := self._data
|
|
100
|
-
b := self._data
|
|
100
|
+
a := self._data(i);
|
|
101
|
+
b := self._data(smallest);
|
|
101
102
|
&(self._data(i)).* = b;
|
|
102
103
|
&(self._data(smallest)).* = a;
|
|
103
104
|
i = smallest;
|
|
@@ -124,11 +125,11 @@ impl(
|
|
|
124
125
|
PriorityQueueIter(T),
|
|
125
126
|
Iterator(
|
|
126
127
|
Item : T,
|
|
127
|
-
next : (fn(self :
|
|
128
|
+
next : (fn(ref(self) : Self) -> Option(T))(
|
|
128
129
|
cond(
|
|
129
130
|
(self._index >= self._data.len()) =>.None,
|
|
130
131
|
true => {
|
|
131
|
-
value := self._data
|
|
132
|
+
value := self._data(self._index);
|
|
132
133
|
self._index = (self._index + usize(1));
|
|
133
134
|
.Some(value)
|
|
134
135
|
}
|
|
@@ -157,7 +158,7 @@ impl(
|
|
|
157
158
|
PriorityQueueIterPtr(T),
|
|
158
159
|
Iterator(
|
|
159
160
|
Item : *(T),
|
|
160
|
-
next : (fn(self :
|
|
161
|
+
next : (fn(ref(self) : Self) -> Option(*(T)))(
|
|
161
162
|
cond(
|
|
162
163
|
(self._index >= self._data.len()) =>.None,
|
|
163
164
|
true =>
|
|
@@ -177,8 +178,8 @@ impl(
|
|
|
177
178
|
impl(
|
|
178
179
|
forall(T : Type),
|
|
179
180
|
PriorityQueue(T),
|
|
180
|
-
iter : (fn(self :
|
|
181
|
-
PriorityQueueIterPtr(T)(_data : self
|
|
181
|
+
iter : (fn(ref(self) : Self) -> PriorityQueueIterPtr(T))(
|
|
182
|
+
PriorityQueueIterPtr(T)(_data : self._data, _index : usize(0))
|
|
182
183
|
)
|
|
183
184
|
);
|
|
184
185
|
export(
|
package/std/crypto/md5.yo
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
//!
|
|
9
9
|
//! digest := md5_hex(data); // "5d41402abc4b2a76b9719d911017c592"
|
|
10
10
|
//! ```
|
|
11
|
+
pragma(Pragma.AllowUnsafe);
|
|
11
12
|
{ ArrayList } :: import("../collections/array_list");
|
|
12
13
|
{ hex_encode } :: import("../encoding/hex");
|
|
13
14
|
open(import("../string"));
|
|
@@ -213,7 +214,7 @@ md5 :: (fn(data : ArrayList(u8)) -> Array(u8, usize(16)))({
|
|
|
213
214
|
rem := (n - i);
|
|
214
215
|
j := usize(0);
|
|
215
216
|
while(j < rem, j = (j + usize(1)), {
|
|
216
|
-
(pad_ptr &+ j).* = data
|
|
217
|
+
(pad_ptr &+ j).* = data(i + j);
|
|
217
218
|
});
|
|
218
219
|
(pad_ptr &+ rem).* = u8(0x80);
|
|
219
220
|
cond(
|
package/std/crypto/random.yo
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
//!
|
|
10
10
|
//! id := uuid_v4(); // "550e8400-e29b-41d4-a716-446655440000"
|
|
11
11
|
//! ```
|
|
12
|
+
pragma(Pragma.AllowUnsafe);
|
|
12
13
|
{ ArrayList } :: import("../collections/array_list");
|
|
13
14
|
{ platform, Platform } :: import("../process");
|
|
14
15
|
open(import("../string"));
|
|
@@ -54,13 +55,15 @@ extern(
|
|
|
54
55
|
// ============================================================================
|
|
55
56
|
// Fill a buffer with cryptographically secure random bytes.
|
|
56
57
|
// ============================================================================
|
|
57
|
-
random_bytes :: (fn(buf :
|
|
58
|
+
random_bytes :: (fn(buf : Slice(u8), exn : Exception) -> unit)({
|
|
59
|
+
buf_ptr := buf.ptr();
|
|
60
|
+
size := buf.len();
|
|
58
61
|
cond(
|
|
59
62
|
(platform == Platform.Macos) => {
|
|
60
|
-
__yo_arc4random_buf(
|
|
63
|
+
__yo_arc4random_buf(buf_ptr, size);
|
|
61
64
|
},
|
|
62
65
|
(platform == Platform.Windows) => {
|
|
63
|
-
r := __yo_bcrypt_gen_random(
|
|
66
|
+
r := __yo_bcrypt_gen_random(buf_ptr, u32(size));
|
|
64
67
|
cond(
|
|
65
68
|
(r == i32(0)) => (),
|
|
66
69
|
true => {
|
|
@@ -77,7 +80,7 @@ random_bytes :: (fn(buf : *(u8), size : usize, exn : Exception) -> unit)(
|
|
|
77
80
|
(remaining > usize(256)) => usize(256),
|
|
78
81
|
true => remaining
|
|
79
82
|
);
|
|
80
|
-
ret := __yo_getentropy(
|
|
83
|
+
ret := __yo_getentropy(buf_ptr &+ offset, chunk);
|
|
81
84
|
cond(
|
|
82
85
|
(ret < i32(0)) => {
|
|
83
86
|
exn.throw(dyn(CryptoError.Unavailable));
|
|
@@ -90,7 +93,7 @@ random_bytes :: (fn(buf : *(u8), size : usize, exn : Exception) -> unit)(
|
|
|
90
93
|
},
|
|
91
94
|
true => {
|
|
92
95
|
// Linux: getrandom syscall
|
|
93
|
-
ret := __yo_getrandom(
|
|
96
|
+
ret := __yo_getrandom(buf_ptr, size, u32(0));
|
|
94
97
|
cond(
|
|
95
98
|
(ret < isize(0)) => {
|
|
96
99
|
exn.throw(dyn(CryptoError.Unavailable));
|
|
@@ -99,27 +102,26 @@ random_bytes :: (fn(buf : *(u8), size : usize, exn : Exception) -> unit)(
|
|
|
99
102
|
);
|
|
100
103
|
}
|
|
101
104
|
)
|
|
102
|
-
);
|
|
105
|
+
});
|
|
103
106
|
export(random_bytes);
|
|
104
107
|
// ============================================================================
|
|
105
108
|
// Typed helpers
|
|
106
109
|
// ============================================================================
|
|
107
110
|
random_u32 :: (fn(exn : Exception) -> u32)({
|
|
108
111
|
buf := Array(u8, usize(4)).fill(u8(0));
|
|
109
|
-
|
|
110
|
-
random_bytes(buf_ptr, usize(4));
|
|
112
|
+
random_bytes(Slice(u8).from_raw_parts(&(buf(usize(0))), usize(4)), exn);
|
|
111
113
|
u32(buf(usize(0))) |
|
|
112
114
|
(u32(buf(usize(1))) << u32(8)) |
|
|
113
115
|
(u32(buf(usize(2))) << u32(16)) |
|
|
114
116
|
(u32(buf(usize(3))) << u32(24))
|
|
115
117
|
});
|
|
116
118
|
random_u64 :: (fn(exn : Exception) -> u64)({
|
|
117
|
-
lo := u64(random_u32());
|
|
118
|
-
hi := u64(random_u32());
|
|
119
|
+
lo := u64(random_u32(exn));
|
|
120
|
+
hi := u64(random_u32(exn));
|
|
119
121
|
lo | (hi << u64(32))
|
|
120
122
|
});
|
|
121
123
|
random_f64 :: (fn(exn : Exception) -> f64)(
|
|
122
|
-
f64(random_u64()) / f64(18446744073709551615.0)
|
|
124
|
+
f64(random_u64(exn)) / f64(18446744073709551615.0)
|
|
123
125
|
);
|
|
124
126
|
// Return a random integer in the half-open range [min, max).
|
|
125
127
|
random_range :: (fn(min : i64, max : i64, exn : Exception) -> i64)({
|
|
@@ -127,7 +129,7 @@ random_range :: (fn(min : i64, max : i64, exn : Exception) -> i64)({
|
|
|
127
129
|
cond(
|
|
128
130
|
(span <= i64(0)) => min,
|
|
129
131
|
true => {
|
|
130
|
-
r := random_u64();
|
|
132
|
+
r := random_u64(exn);
|
|
131
133
|
min + i64(r % u64(span))
|
|
132
134
|
}
|
|
133
135
|
)
|
|
@@ -140,8 +142,7 @@ export(random_u32, random_u64, random_f64, random_range);
|
|
|
140
142
|
uuid_v4 :: (fn(exn : Exception) -> String)({
|
|
141
143
|
bytes := ArrayList(u8).with_capacity(usize(16));
|
|
142
144
|
buf := Array(u8, usize(16)).fill(u8(0));
|
|
143
|
-
|
|
144
|
-
random_bytes(buf_ptr, usize(16));
|
|
145
|
+
random_bytes(Slice(u8).from_raw_parts(&(buf(usize(0))), usize(16)), exn);
|
|
145
146
|
// Set version bits (v4)
|
|
146
147
|
buf(usize(6)) = ((buf(usize(6)) & u8(0x0F)) | u8(0x40));
|
|
147
148
|
// Set variant bits
|
|
@@ -165,7 +166,7 @@ uuid_v4 :: (fn(exn : Exception) -> String)({
|
|
|
165
166
|
},
|
|
166
167
|
true => ()
|
|
167
168
|
);
|
|
168
|
-
out.push(hex_bytes
|
|
169
|
+
out.push(hex_bytes(j));
|
|
169
170
|
});
|
|
170
171
|
String.from_bytes(out)
|
|
171
172
|
});
|
package/std/crypto/sha256.yo
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
//!
|
|
8
8
|
//! digest := sha256_hex(data); // "2cf24dba..."
|
|
9
9
|
//! ```
|
|
10
|
+
pragma(Pragma.AllowUnsafe);
|
|
10
11
|
{ ArrayList } :: import("../collections/array_list");
|
|
11
12
|
{ hex_encode } :: import("../encoding/hex");
|
|
12
13
|
open(import("../string"));
|
|
@@ -176,7 +177,7 @@ impl(
|
|
|
176
177
|
update : (fn(self : Self, data : ArrayList(u8)) -> Self)({
|
|
177
178
|
i := usize(0);
|
|
178
179
|
while(i < data.len(), i = (i + usize(1)), {
|
|
179
|
-
self._buf(self._buflen) = data
|
|
180
|
+
self._buf(self._buflen) = data(i);
|
|
180
181
|
self._buflen = (self._buflen + usize(1));
|
|
181
182
|
self._total = (self._total + u64(1));
|
|
182
183
|
cond(
|
package/std/encoding/base64.yo
CHANGED
|
@@ -26,9 +26,9 @@ _encode_with :: (fn(data : ArrayList(u8), alpha : str, pad : bool) -> String)({
|
|
|
26
26
|
out := ArrayList(u8).with_capacity(((n + usize(2)) / usize(3)) * usize(4));
|
|
27
27
|
i := usize(0);
|
|
28
28
|
while(i < n, i = (i + usize(3)), {
|
|
29
|
-
b0 := data
|
|
30
|
-
b1 := cond(((i + usize(1)) < n) => data
|
|
31
|
-
b2 := cond(((i + usize(2)) < n) => data
|
|
29
|
+
b0 := data(i);
|
|
30
|
+
b1 := cond(((i + usize(1)) < n) => data(i + usize(1)), true => u8(0));
|
|
31
|
+
b2 := cond(((i + usize(2)) < n) => data(i + usize(2)), true => u8(0));
|
|
32
32
|
out.push(alpha.bytes(usize(b0 >> u8(2))));
|
|
33
33
|
out.push(alpha.bytes(usize(((b0 & u8(3)) << u8(4)) | (b1 >> u8(4)))));
|
|
34
34
|
cond(
|
|
@@ -83,19 +83,19 @@ _decode_with :: (fn(s : str, alpha : str, exn : Exception) -> ArrayList(u8))({
|
|
|
83
83
|
out := ArrayList(u8).with_capacity((len * usize(3)) / usize(4));
|
|
84
84
|
i := usize(0);
|
|
85
85
|
while(i < len, i = (i + usize(4)), {
|
|
86
|
-
c0 := _decode_char(s.bytes(i), alpha);
|
|
86
|
+
c0 := _decode_char(s.bytes(i), alpha, exn);
|
|
87
87
|
c1 := cond(
|
|
88
|
-
((i + usize(1)) < len) => _decode_char(s.bytes(i + usize(1)), alpha),
|
|
88
|
+
((i + usize(1)) < len) => _decode_char(s.bytes(i + usize(1)), alpha, exn),
|
|
89
89
|
true => u8(0)
|
|
90
90
|
);
|
|
91
91
|
out.push((c0 << u8(2)) | (c1 >> u8(4)));
|
|
92
92
|
cond(
|
|
93
93
|
((i + usize(2)) < len) => {
|
|
94
|
-
c2 := _decode_char(s.bytes(i + usize(2)), alpha);
|
|
94
|
+
c2 := _decode_char(s.bytes(i + usize(2)), alpha, exn);
|
|
95
95
|
out.push(((c1 & u8(15)) << u8(4)) | (c2 >> u8(2)));
|
|
96
96
|
cond(
|
|
97
97
|
((i + usize(3)) < len) => {
|
|
98
|
-
c3 := _decode_char(s.bytes(i + usize(3)), alpha);
|
|
98
|
+
c3 := _decode_char(s.bytes(i + usize(3)), alpha, exn);
|
|
99
99
|
out.push(((c2 & u8(3)) << u8(6)) | c3);
|
|
100
100
|
},
|
|
101
101
|
true => ()
|
|
@@ -108,11 +108,11 @@ _decode_with :: (fn(s : str, alpha : str, exn : Exception) -> ArrayList(u8))({
|
|
|
108
108
|
});
|
|
109
109
|
/// Decode a standard base64 string to bytes. Throws via `Exception` on invalid input.
|
|
110
110
|
base64_decode :: (fn(s : str, exn : Exception) -> ArrayList(u8))(
|
|
111
|
-
_decode_with(s, _STD_ALPHA)
|
|
111
|
+
_decode_with(s, _STD_ALPHA, exn)
|
|
112
112
|
);
|
|
113
113
|
/// Decode a URL-safe base64 string to bytes. Throws via `Exception` on invalid input.
|
|
114
114
|
base64_decode_url :: (fn(s : str, exn : Exception) -> ArrayList(u8))(
|
|
115
|
-
_decode_with(s, _URL_ALPHA)
|
|
115
|
+
_decode_with(s, _URL_ALPHA, exn)
|
|
116
116
|
);
|
|
117
117
|
export(base64_decode, base64_decode_url);
|
|
118
118
|
// ============================================================================
|
|
@@ -152,11 +152,11 @@ base64_decode_string :: (fn(input : String) -> Result(String, String))({
|
|
|
152
152
|
});
|
|
153
153
|
// Strip trailing padding
|
|
154
154
|
len := cleaned.len();
|
|
155
|
-
while((len > usize(0)) && (cleaned
|
|
155
|
+
while((len > usize(0)) && (cleaned(len - usize(1)) == u8(61)), len = (len - usize(1)), ());
|
|
156
156
|
out := ArrayList(u8).new();
|
|
157
157
|
j := usize(0);
|
|
158
158
|
while(j < len, j = (j + usize(4)), {
|
|
159
|
-
v0 := _base64_index(cleaned
|
|
159
|
+
v0 := _base64_index(cleaned(j));
|
|
160
160
|
cond(
|
|
161
161
|
(v0 == i32(-(1))) => {
|
|
162
162
|
return(.Err(`Invalid base64 input`));
|
|
@@ -165,7 +165,7 @@ base64_decode_string :: (fn(input : String) -> Result(String, String))({
|
|
|
165
165
|
);
|
|
166
166
|
v1 := cond(
|
|
167
167
|
((j + usize(1)) < len) => {
|
|
168
|
-
tmp := _base64_index(cleaned
|
|
168
|
+
tmp := _base64_index(cleaned(j + usize(1)));
|
|
169
169
|
cond(
|
|
170
170
|
(tmp == i32(-(1))) => {
|
|
171
171
|
return(.Err(`Invalid base64 input`));
|
|
@@ -179,7 +179,7 @@ base64_decode_string :: (fn(input : String) -> Result(String, String))({
|
|
|
179
179
|
out.push(u8((v0 << i32(2)) | (v1 >> i32(4))));
|
|
180
180
|
cond(
|
|
181
181
|
((j + usize(2)) < len) => {
|
|
182
|
-
v2 := _base64_index(cleaned
|
|
182
|
+
v2 := _base64_index(cleaned(j + usize(2)));
|
|
183
183
|
cond(
|
|
184
184
|
(v2 == i32(-(1))) => {
|
|
185
185
|
return(.Err(`Invalid base64 input`));
|
|
@@ -189,7 +189,7 @@ base64_decode_string :: (fn(input : String) -> Result(String, String))({
|
|
|
189
189
|
out.push(u8(((v1 & i32(15)) << i32(4)) | (v2 >> i32(2))));
|
|
190
190
|
cond(
|
|
191
191
|
((j + usize(3)) < len) => {
|
|
192
|
-
v3 := _base64_index(cleaned
|
|
192
|
+
v3 := _base64_index(cleaned(j + usize(3)));
|
|
193
193
|
cond(
|
|
194
194
|
(v3 == i32(-(1))) => {
|
|
195
195
|
return(.Err(`Invalid base64 input`));
|
package/std/encoding/hex.yo
CHANGED
|
@@ -48,7 +48,7 @@ _hex_encode_impl :: (fn(data : ArrayList(u8), hex_chars : str) -> String)({
|
|
|
48
48
|
out := ArrayList(u8).with_capacity(data.len() * usize(2));
|
|
49
49
|
i := usize(0);
|
|
50
50
|
while(i < data.len(), i = (i + usize(1)), {
|
|
51
|
-
b := data
|
|
51
|
+
b := data(i);
|
|
52
52
|
hi := usize((b >> u8(4)) & u8(0xF));
|
|
53
53
|
lo := usize(b & u8(0xF));
|
|
54
54
|
out.push(hex_chars.bytes(hi));
|
|
@@ -86,8 +86,8 @@ hex_decode :: (fn(s : str, exn : Exception) -> ArrayList(u8))({
|
|
|
86
86
|
out := ArrayList(u8).with_capacity(s.len() / usize(2));
|
|
87
87
|
i := usize(0);
|
|
88
88
|
while(i < s.len(), i = (i + usize(2)), {
|
|
89
|
-
hi := _hex_nibble(s.bytes(i));
|
|
90
|
-
lo := _hex_nibble(s.bytes(i + usize(1)));
|
|
89
|
+
hi := _hex_nibble(s.bytes(i), exn);
|
|
90
|
+
lo := _hex_nibble(s.bytes(i + usize(1)), exn);
|
|
91
91
|
out.push((hi << u8(4)) | lo);
|
|
92
92
|
});
|
|
93
93
|
out
|