@shd101wyy/yo 0.0.23 → 0.0.25

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.
Files changed (97) hide show
  1. package/out/cjs/index.cjs +560 -520
  2. package/out/cjs/yo-cli.cjs +598 -558
  3. package/out/esm/index.mjs +551 -511
  4. package/out/types/src/codegen/exprs/arc.d.ts +5 -0
  5. package/out/types/src/codegen/types/generation.d.ts +2 -0
  6. package/out/types/src/codegen/utils/index.d.ts +8 -1
  7. package/out/types/src/evaluator/builtins/rc-fns.d.ts +5 -0
  8. package/out/types/src/evaluator/calls/arc.d.ts +15 -0
  9. package/out/types/src/evaluator/calls/trait-type.d.ts +8 -1
  10. package/out/types/src/evaluator/context.d.ts +11 -1
  11. package/out/types/src/evaluator/types/utils.d.ts +8 -3
  12. package/out/types/src/evaluator/utils/closure.d.ts +7 -1
  13. package/out/types/src/evaluator/values/impl.d.ts +8 -0
  14. package/out/types/src/expr.d.ts +6 -0
  15. package/out/types/src/test-runner.d.ts +2 -0
  16. package/out/types/src/types/creators.d.ts +2 -1
  17. package/out/types/src/types/definitions.d.ts +10 -0
  18. package/out/types/src/types/guards.d.ts +2 -1
  19. package/out/types/src/types/tags.d.ts +1 -0
  20. package/out/types/tsconfig.tsbuildinfo +1 -1
  21. package/package.json +1 -1
  22. package/std/collections/array_list.yo +80 -10
  23. package/std/collections/btree_map.yo +120 -2
  24. package/std/collections/deque.yo +98 -6
  25. package/std/collections/hash_map.yo +137 -1
  26. package/std/collections/hash_set.yo +85 -1
  27. package/std/collections/linked_list.yo +61 -1
  28. package/std/collections/priority_queue.yo +70 -1
  29. package/std/crypto/md5.yo +4 -4
  30. package/std/crypto/random.yo +3 -3
  31. package/std/crypto/sha256.yo +8 -7
  32. package/std/encoding/base64.yo +6 -6
  33. package/std/encoding/hex.yo +27 -22
  34. package/std/encoding/json.yo +185 -186
  35. package/std/encoding/utf16.yo +2 -2
  36. package/std/fmt/display.yo +1 -1
  37. package/std/fmt/writer.yo +2 -4
  38. package/std/fs/dir.yo +5 -5
  39. package/std/fs/file.yo +21 -13
  40. package/std/fs/metadata.yo +4 -4
  41. package/std/fs/temp.yo +3 -3
  42. package/std/fs/types.yo +1 -1
  43. package/std/fs/walker.yo +1 -1
  44. package/std/net/addr.yo +2 -2
  45. package/std/net/dns.yo +21 -20
  46. package/std/net/errors.yo +1 -1
  47. package/std/net/tcp.yo +134 -100
  48. package/std/net/udp.yo +51 -42
  49. package/std/os/env.yo +21 -23
  50. package/std/os/signal.yo +10 -9
  51. package/std/prelude.yo +158 -22
  52. package/std/string/string.yo +99 -1
  53. package/std/sync/once.yo +1 -1
  54. package/std/{io → sys}/advise.yo +1 -1
  55. package/std/sys/bufio/buf_reader.yo +300 -0
  56. package/std/sys/bufio/buf_writer.yo +168 -0
  57. package/std/{io → sys}/clock.yo +1 -1
  58. package/std/{io → sys}/constants.yo +1 -1
  59. package/std/{io → sys}/copy.yo +1 -1
  60. package/std/{io → sys}/dir.yo +6 -6
  61. package/std/{io → sys}/dns.yo +3 -3
  62. package/std/{io → sys}/errors.yo +1 -1
  63. package/std/{io → sys}/events.yo +1 -1
  64. package/std/{io → sys}/externs.yo +1 -1
  65. package/std/{io → sys}/fallocate.yo +1 -1
  66. package/std/{io → sys}/fcntl.yo +1 -1
  67. package/std/{io → sys}/file.yo +1 -1
  68. package/std/{io → sys}/future.yo +1 -1
  69. package/std/{io → sys}/iov.yo +1 -1
  70. package/std/{io → sys}/lock.yo +1 -1
  71. package/std/{io → sys}/mmap.yo +1 -1
  72. package/std/{io → sys}/path.yo +1 -1
  73. package/std/{io → sys}/perm.yo +3 -3
  74. package/std/{io → sys}/pipe.yo +1 -1
  75. package/std/{io → sys}/process.yo +1 -1
  76. package/std/{io → sys}/seek.yo +1 -1
  77. package/std/{io → sys}/signal.yo +1 -1
  78. package/std/{io → sys}/signals.yo +1 -1
  79. package/std/{io → sys}/socket.yo +1 -1
  80. package/std/{io → sys}/socketpair.yo +1 -1
  81. package/std/{io → sys}/sockinfo.yo +1 -1
  82. package/std/{io → sys}/statfs.yo +2 -2
  83. package/std/{io → sys}/statx.yo +1 -1
  84. package/std/{io → sys}/sysinfo.yo +1 -1
  85. package/std/{io → sys}/tcp.yo +3 -3
  86. package/std/{io → sys}/temp.yo +1 -1
  87. package/std/{io → sys}/time.yo +2 -2
  88. package/std/{io → sys}/timer.yo +1 -1
  89. package/std/{io → sys}/tty.yo +1 -1
  90. package/std/{io → sys}/udp.yo +4 -4
  91. package/std/{io → sys}/umask.yo +1 -1
  92. package/std/{io → sys}/unix.yo +1 -1
  93. package/std/time/datetime.yo +18 -23
  94. package/std/time/instant.yo +13 -11
  95. package/std/url/url.yo +533 -0
  96. package/std/math/functions.yo +0 -74
  97. package/std/math/random.yo +0 -94
package/std/net/udp.yo CHANGED
@@ -1,6 +1,6 @@
1
1
  // std/net/udp.yo - High-level UDP socket
2
2
  //
3
- // Wraps std/io/udp with typed UdpSocket object.
3
+ // Wraps std/sys/udp with typed UdpSocket object.
4
4
  //
5
5
  // Example:
6
6
  // { UdpSocket } :: import "std/net/udp";
@@ -23,13 +23,14 @@
23
23
  open import "../string";
24
24
  open import "../fmt";
25
25
  { NetError } :: import "./errors";
26
+ { IOError } :: import "../sys/errors";
26
27
  { IpAddr, SocketAddr } :: import "./addr";
27
- IO_udp :: import "../io/udp";
28
- IO_tcp :: import "../io/tcp";
28
+ IO_udp :: import "../sys/udp";
29
+ IO_tcp :: import "../sys/tcp";
29
30
  {
30
31
  AF_INET, AF_INET6, SOCK_DGRAM,
31
32
  SOL_SOCKET, SO_BROADCAST
32
- } :: import "../io/socket";
33
+ } :: import "../sys/socket";
33
34
  { snprintf } :: import "../libc/stdio";
34
35
 
35
36
  // ============================================================================
@@ -40,12 +41,11 @@ _make_sockaddr :: (fn(addr: SocketAddr) -> IO_tcp.SockAddr)(
40
41
  match(addr.ip,
41
42
  .V4(a, b, c, d) => {
42
43
  buf := Array(u8, usize(16)).fill(u8(0));
43
- snprintf(&(buf(usize(0))), usize(16), "%d.%d.%d.%d", i32(a), i32(b), i32(c), i32(d));
44
+ snprintf(*(char)(&(buf(usize(0)))), usize(16), "%d.%d.%d.%d", i32(a), i32(b), i32(c), i32(d));
44
45
  IO_tcp.make_sockaddr_in(&(buf(usize(0))), addr.port)
45
46
  },
46
- .V6(_) => {
47
+ .V6(_) =>
47
48
  IO_tcp.make_sockaddr_in6(*(u8)("::1"), addr.port)
48
- }
49
49
  )
50
50
  );
51
51
 
@@ -61,8 +61,8 @@ UdpSocket :: object(
61
61
 
62
62
  impl(UdpSocket,
63
63
  // Create and bind a UDP socket to the given address.
64
- bind : (fn(addr: SocketAddr, using(io : IO)) -> Impl(Future(Result(UdpSocket, NetError))))({
65
- task := io.async((using(io : IO)) => {
64
+ bind : (fn(addr: SocketAddr, using(io : IO)) -> Impl(Future(Result(UdpSocket, NetError), IO)))(
65
+ io.async((using(io : IO)) => {
66
66
  domain := cond(
67
67
  addr.ip.is_v4() => AF_INET,
68
68
  true => AF_INET6
@@ -70,7 +70,8 @@ impl(UdpSocket,
70
70
  fd := io.await(IO_udp.socket(domain, i32(0)));
71
71
  cond(
72
72
  (fd < i32(0)) => {
73
- return .Err(NetError.from_result(fd).unwrap_err());
73
+ (ret : Result(UdpSocket, NetError)) = .Err(NetError.from_io(IOError.from_errno((i32(0) - fd))));
74
+ return ret;
74
75
  },
75
76
  true => ()
76
77
  );
@@ -80,81 +81,89 @@ impl(UdpSocket,
80
81
  cond(
81
82
  (bind_result < i32(0)) => {
82
83
  io.await(IO_udp.close(fd));
83
- return .Err(NetError.from_result(bind_result).unwrap_err());
84
+ (ret : Result(UdpSocket, NetError)) = .Err(NetError.from_io(IOError.from_errno((i32(0) - bind_result))));
85
+ return ret;
84
86
  },
85
87
  true => ()
86
88
  );
87
- return .Ok(UdpSocket(_fd: fd, _local_addr: addr, _is_closed: false));
88
- });
89
- return task;
90
- }),
89
+ (ret : Result(UdpSocket, NetError)) = .Ok(UdpSocket(_fd: fd, _local_addr: addr, _is_closed: false));
90
+ return ret;
91
+ })
92
+ ),
91
93
 
92
94
  // Send a datagram to a specific address.
93
95
  // Returns the number of bytes sent.
94
- send_to : (fn(self: Self, data: ArrayList(u8), addr: SocketAddr, using(io : IO)) -> Impl(Future(Result(i32, NetError))))({
96
+ send_to : (fn(self: Self, data: ArrayList(u8), addr: SocketAddr, using(io : IO)) -> Impl(Future(Result(i32, NetError), IO)))({
95
97
  fd := self._fd;
96
- task := io.async((using(io : IO)) => {
98
+ io.async((using(io : IO)) => {
97
99
  saddr := _make_sockaddr(addr);
98
100
  result := io.await(IO_udp.sendto(fd, data.ptr().unwrap(), data.len(), i32(0), saddr.buf, saddr.len));
99
101
  IO_tcp.free_sockaddr(saddr);
100
102
  NetError.from_result(result)
101
- });
102
- return task;
103
+ })
103
104
  }),
104
105
 
105
106
  // Receive a datagram.
106
107
  // Returns the number of bytes received.
107
- recv : (fn(self: Self, buf: *(u8), size: usize, using(io : IO)) -> Impl(Future(Result(i32, NetError))))({
108
+ recv : (fn(self: Self, buf: *(u8), size: usize, using(io : IO)) -> Impl(Future(Result(i32, NetError), IO)))({
108
109
  fd := self._fd;
109
- task := io.async((using(io : IO)) => {
110
+ io.async((using(io : IO)) => {
110
111
  result := io.await(IO_udp.recv(fd, buf, size, i32(0)));
111
112
  NetError.from_result(result)
112
- });
113
- return task;
113
+ })
114
+ }),
115
+
116
+ // Receive a datagram and get the source address.
117
+ // Returns the number of bytes received.
118
+ recv_from : (fn(self: Self, buf: *(u8), size: usize, src_addr: *(u8), src_addr_len: *(u32), using(io : IO)) -> Impl(Future(Result(i32, NetError), IO)))({
119
+ fd := self._fd;
120
+ io.async((using(io : IO)) => {
121
+ result := io.await(IO_udp.recvfrom(fd, buf, size, i32(0), src_addr, src_addr_len));
122
+ NetError.from_result(result)
123
+ })
114
124
  }),
115
125
 
116
126
  // Send data on a connected socket (after connect()).
117
- send : (fn(self: Self, data: ArrayList(u8), using(io : IO)) -> Impl(Future(Result(i32, NetError))))({
127
+ send : (fn(self: Self, data: ArrayList(u8), using(io : IO)) -> Impl(Future(Result(i32, NetError), IO)))({
118
128
  fd := self._fd;
119
- task := io.async((using(io : IO)) => {
129
+ io.async((using(io : IO)) => {
120
130
  result := io.await(IO_udp.send(fd, data.ptr().unwrap(), data.len(), i32(0)));
121
131
  NetError.from_result(result)
122
- });
123
- return task;
132
+ })
124
133
  }),
125
134
 
126
135
  // Close the socket.
127
- close : (fn(self: Self, using(io : IO)) -> Impl(Future(Result(unit, NetError))))({
136
+ close : (fn(self: Self, using(io : IO)) -> Impl(Future(Result(unit, NetError), IO)))({
128
137
  fd := self._fd;
129
- task := io.async((using(io : IO)) => {
130
- cond(
138
+ io.async((using(io : IO)) => {
139
+ (ret : Result(unit, NetError)) = cond(
131
140
  self._is_closed => .Ok(()),
132
141
  true => {
133
142
  result := io.await(IO_udp.close(fd));
134
143
  self._is_closed = true;
135
144
  cond(
136
- (result < i32(0)) => .Err(NetError.from_result(result).unwrap_err()),
145
+ (result < i32(0)) => .Err(NetError.from_io(IOError.from_errno((i32(0) - result)))),
137
146
  true => .Ok(())
138
147
  )
139
148
  }
140
- )
141
- });
142
- return task;
149
+ );
150
+ ret
151
+ })
143
152
  }),
144
153
 
145
154
  // Enable/disable SO_BROADCAST.
146
- set_broadcast : (fn(self: Self, enabled: bool, using(io : IO)) -> Impl(Future(Result(unit, NetError))))({
155
+ set_broadcast : (fn(self: Self, enabled: bool, using(io : IO)) -> Impl(Future(Result(unit, NetError), IO)))({
147
156
  fd := self._fd;
148
- task := io.async((using(io : IO)) => {
157
+ io.async((using(io : IO)) => {
149
158
  val := cond(enabled => i32(1), true => i32(0));
150
159
  val_ptr := &val;
151
160
  result := io.await(IO_udp.setsockopt(fd, SOL_SOCKET, SO_BROADCAST, *(u8)(val_ptr), u32(4)));
152
- cond(
153
- (result < i32(0)) => .Err(NetError.from_result(result).unwrap_err()),
161
+ (ret : Result(unit, NetError)) = cond(
162
+ (result < i32(0)) => .Err(NetError.from_io(IOError.from_errno((i32(0) - result)))),
154
163
  true => .Ok(())
155
- )
156
- });
157
- return task;
164
+ );
165
+ ret
166
+ })
158
167
  }),
159
168
 
160
169
  // Get the local address.
@@ -172,7 +181,7 @@ impl(UdpSocket, Dispose(
172
181
  dispose : (fn(self: Self) -> unit)({
173
182
  cond(
174
183
  (!(self._is_closed)) => {
175
- { close_sync } :: import "../io/file";
184
+ { close_sync } :: import "../sys/file";
176
185
  close_sync(self._fd);
177
186
  self._is_closed = true;
178
187
  },
package/std/os/env.yo CHANGED
@@ -16,35 +16,33 @@ open import "../string";
16
16
  // ============================================================================
17
17
 
18
18
  // Return the current user's home directory, or .None if unavailable.
19
- home_dir :: (fn() -> ?String)(
19
+ home_dir :: (fn() -> Option(String))(
20
20
  cond(
21
- (platform == Platform.Win32) => {
22
- match(env.get(String.from("USERPROFILE")),
23
- .Some(p) => .Some(p),
24
- .None => match(env.get(String.from("HOMEDRIVE")),
21
+ (platform == Platform.Win32) => match(env.get(`USERPROFILE`),
22
+ .Some(p) => .Some(p),
23
+ .None => match(env.get(`HOMEDRIVE`),
24
+ .None => .None,
25
+ .Some(drive) => match(env.get(`HOMEPATH`),
25
26
  .None => .None,
26
- .Some(drive) => match(env.get(String.from("HOMEPATH")),
27
- .None => .None,
28
- .Some(path) => .Some(drive.concat(path))
29
- )
27
+ .Some(path) => .Some(drive.concat(path))
30
28
  )
31
29
  )
32
- },
33
- true => env.get(String.from("HOME"))
30
+ ),
31
+ true => env.get(`HOME`)
34
32
  )
35
33
  );
36
34
 
37
35
  // Return the user-specific configuration directory.
38
36
  // Linux/macOS: $XDG_CONFIG_HOME or $HOME/.config
39
37
  // Windows: %APPDATA%
40
- config_dir :: (fn() -> ?String)(
38
+ config_dir :: (fn() -> Option(String))(
41
39
  cond(
42
- (platform == Platform.Win32) => env.get(String.from("APPDATA")),
43
- true => match(env.get(String.from("XDG_CONFIG_HOME")),
40
+ (platform == Platform.Win32) => env.get(`APPDATA`),
41
+ true => match(env.get(`XDG_CONFIG_HOME`),
44
42
  .Some(d) => .Some(d),
45
43
  .None => match(home_dir(),
46
44
  .None => .None,
47
- .Some(h) => .Some(h.concat(String.from("/.config")))
45
+ .Some(h) => .Some(h.concat(`/.config`))
48
46
  )
49
47
  )
50
48
  )
@@ -54,18 +52,18 @@ config_dir :: (fn() -> ?String)(
54
52
  // Linux: $XDG_CACHE_HOME or $HOME/.cache
55
53
  // macOS: $HOME/Library/Caches
56
54
  // Windows: %LOCALAPPDATA%
57
- cache_dir :: (fn() -> ?String)(
55
+ cache_dir :: (fn() -> Option(String))(
58
56
  cond(
59
- (platform == Platform.Win32) => env.get(String.from("LOCALAPPDATA")),
57
+ (platform == Platform.Win32) => env.get(`LOCALAPPDATA`),
60
58
  (platform == Platform.Darwin) => match(home_dir(),
61
59
  .None => .None,
62
- .Some(h) => .Some(h.concat(String.from("/Library/Caches")))
60
+ .Some(h) => .Some(h.concat(`/Library/Caches`))
63
61
  ),
64
- true => match(env.get(String.from("XDG_CACHE_HOME")),
62
+ true => match(env.get(`XDG_CACHE_HOME`),
65
63
  .Some(d) => .Some(d),
66
64
  .None => match(home_dir(),
67
65
  .None => .None,
68
- .Some(h) => .Some(h.concat(String.from("/.cache")))
66
+ .Some(h) => .Some(h.concat(`/.cache`))
69
67
  )
70
68
  )
71
69
  )
@@ -74,11 +72,11 @@ cache_dir :: (fn() -> ?String)(
74
72
  // Return the system temporary directory.
75
73
  temp_dir :: (fn() -> String)(
76
74
  cond(
77
- (platform == Platform.Win32) => match(env.get(String.from("TEMP")),
75
+ (platform == Platform.Win32) => match(env.get(`TEMP`),
78
76
  .Some(t) => t,
79
- .None => String.from("C:\\Temp")
77
+ .None => `C:\Temp`
80
78
  ),
81
- true => String.from("/tmp")
79
+ true => `/tmp`
82
80
  )
83
81
  );
84
82
 
package/std/os/signal.yo CHANGED
@@ -1,16 +1,17 @@
1
1
  // std/os/signal.yo - High-level signal handling
2
2
  //
3
- // Wraps std/io/signal with typed Signal enum values.
3
+ // Wraps std/sys/signal with typed Signal enum values.
4
4
  //
5
5
  // Example:
6
- // { on_signal, Signal } :: import "std/os/signal";
6
+ // { on_signal, off_signal, Signal, SignalHandler } :: import "std/os/signal";
7
7
  //
8
- // on_signal(.Interrupt, () => { println("Caught SIGINT"); });
8
+ // handler :: (fn(data: *(u8)) -> unit)({ println("Caught SIGINT"); });
9
+ // on_signal(.Interrupt, handler);
9
10
 
10
- { IOError } :: import "../io/errors";
11
+ { IOError } :: import "../sys/errors";
11
12
  {
12
- on_signal : _on_signal, off_signal : _off_signal
13
- } :: import "../io/signal";
13
+ on_signal : _on_signal, off_signal : _off_signal, SignalHandler
14
+ } :: import "../sys/signal";
14
15
  { platform, Platform } :: import "../process";
15
16
 
16
17
  // ============================================================================
@@ -72,9 +73,9 @@ _signal_num :: (fn(sig: Signal) -> i32)(
72
73
  // ============================================================================
73
74
 
74
75
  // Register a handler for the given signal.
75
- on_signal :: (fn(sig: Signal, handler: Impl(Fn() -> unit)) -> Result(unit, IOError))({
76
+ on_signal :: (fn(sig: Signal, handler: SignalHandler) -> Result(unit, IOError))({
76
77
  num := _signal_num(sig);
77
- r := _on_signal(num, (data) => { handler(); });
78
+ r := _on_signal(num, handler);
78
79
  cond(
79
80
  (r < i32(0)) => .Err(IOError.from_errno((i32(0) - r))),
80
81
  true => .Ok(())
@@ -91,4 +92,4 @@ off_signal :: (fn(sig: Signal) -> Result(unit, IOError))({
91
92
  )
92
93
  });
93
94
 
94
- export on_signal, off_signal;
95
+ export SignalHandler, on_signal, off_signal;
package/std/prelude.yo CHANGED
@@ -94,6 +94,8 @@ extern "Yo",
94
94
  // slice related
95
95
  __yo_slice_len :
96
96
  fn(forall(T: Type), slice: Slice(T)) -> usize,
97
+ __yo_slice_new :
98
+ fn(forall(T: Type), ptr: *(T), length: usize) -> Slice(T),
97
99
 
98
100
  // C macro related
99
101
  __yo_c_macro_defined : (fn(comptime(name) : comptime_string) -> comptime(bool)),
@@ -118,10 +120,8 @@ export assert;
118
120
 
119
121
  // unsafe module
120
122
  unsafe :: impl {
121
- drop :: (fn(forall(T : Type), own(value) : T) -> unit) {
122
- ___drop(value);
123
- ()
124
- };
123
+ drop :: (fn(quote(value) : Expr) -> unquote(Expr))
124
+ quote(___drop(unquote(value)));
125
125
  export drop;
126
126
  };
127
127
  export unsafe;
@@ -3188,6 +3188,9 @@ impl(forall(T : Type), Slice(T), Acyclic());
3188
3188
  impl(forall(T : Type), where(T <: Comptime), Slice(T), Comptime());
3189
3189
  impl(forall(T : Type), where(T <: Runtime), Slice(T), Runtime());
3190
3190
  impl(forall(T : Type), Slice(T),
3191
+ from_raw_parts : (fn(ptr : *(T), length : usize) -> Self)(
3192
+ __yo_slice_new(ptr, length)
3193
+ ),
3191
3194
  len : (fn(self : Self) -> usize)(
3192
3195
  __yo_slice_len(self)
3193
3196
  )
@@ -3198,10 +3201,65 @@ str :: newtype(
3198
3201
  bytes : Slice(u8)
3199
3202
  );
3200
3203
  impl(str,
3204
+ from_raw_parts : (fn(ptr : *(u8), length : usize) -> Self)(
3205
+ Self(bytes: __yo_slice_new(ptr, length))
3206
+ ),
3201
3207
  len : (fn(self : Self) -> usize)(
3202
3208
  __yo_slice_len(self.bytes)
3203
3209
  )
3204
3210
  );
3211
+
3212
+ impl(str, Eq(str)(
3213
+ (==) : (fn(lhs: Self, rhs: Self) -> bool)({
3214
+ lhs_len := lhs.len();
3215
+ cond(
3216
+ (lhs_len != rhs.len()) => {
3217
+ return false;
3218
+ },
3219
+ true => ()
3220
+ );
3221
+ i := usize(0);
3222
+ while (i < lhs_len), (i = (i + usize(1))), {
3223
+ cond(
3224
+ (lhs.bytes(i) != rhs.bytes(i)) => {
3225
+ return false;
3226
+ },
3227
+ true => ()
3228
+ );
3229
+ };
3230
+ true
3231
+ }),
3232
+ (!=) : (fn(lhs: Self, rhs: Self) -> bool)({
3233
+ return !(Self.(==)(lhs, rhs));
3234
+ })
3235
+ ));
3236
+
3237
+ impl(str, Ord(str)(
3238
+ (<) : (fn(lhs: Self, rhs: Self) -> bool)({
3239
+ lhs_len := lhs.len();
3240
+ rhs_len := rhs.len();
3241
+ min_len := cond((lhs_len < rhs_len) => lhs_len, true => rhs_len);
3242
+ i := usize(0);
3243
+ while (i < min_len), (i = (i + usize(1))), {
3244
+ cond(
3245
+ (lhs.bytes(i) < rhs.bytes(i)) => { return true; },
3246
+ (lhs.bytes(i) > rhs.bytes(i)) => { return false; },
3247
+ true => ()
3248
+ );
3249
+ };
3250
+ (lhs_len < rhs_len)
3251
+ }),
3252
+ (<=) : (fn(lhs: Self, rhs: Self) -> bool)({
3253
+ return !(rhs < lhs);
3254
+ }),
3255
+ (>) : (fn(lhs: Self, rhs: Self) -> bool)({
3256
+ return (rhs < lhs);
3257
+ }),
3258
+ (>=) : (fn(lhs: Self, rhs: Self) -> bool)({
3259
+ return !(lhs < rhs);
3260
+ })
3261
+ ));
3262
+
3205
3263
  export str;
3206
3264
 
3207
3265
 
@@ -3380,6 +3438,13 @@ impl(forall(OkType : Type, ErrorType : Type), Result(OkType, ErrorType),
3380
3438
  )
3381
3439
  ),
3382
3440
 
3441
+ unwrap_err : (fn(self : Self) -> ErrorType)(
3442
+ match(self,
3443
+ .Err(error) => error,
3444
+ .Ok(_) => panic("Called unwrap_err on an Ok value")
3445
+ )
3446
+ ),
3447
+
3383
3448
  is_ok : (fn(self : Self) -> bool)(
3384
3449
  match(self,
3385
3450
  .Ok(_) => true,
@@ -3487,6 +3552,14 @@ impl(forall(T : Type), Iso(T),
3487
3552
  });
3488
3553
  export (^);
3489
3554
 
3555
+ /// === Arc ===
3556
+ arc :: (fn(forall(T : Type), own(value) : T) -> Arc(T))
3557
+ Arc(T)(value)
3558
+ ;
3559
+ impl(forall(T : Type), Arc(T), Send());
3560
+
3561
+ export arc;
3562
+
3490
3563
  /// === MaybeUninit ===
3491
3564
  extern "Yo",
3492
3565
  __yo_maybe_uninit_new :
@@ -3534,29 +3607,92 @@ export
3534
3607
 
3535
3608
  // === Traits again ===
3536
3609
  /// === Iterator ===
3537
- Iterator :: (fn(comptime(Item) : Type) -> comptime(Trait)) {
3538
- return trait(
3539
- Item := Item,
3540
- next :
3541
- fn(self : *(Self)) -> Option(Self.Item)
3542
- );
3543
- };
3610
+ Iterator :: trait(
3611
+ Item : Type,
3612
+ next :
3613
+ fn(self : *(Self)) -> Option(Self.Item)
3614
+ );
3544
3615
  export Iterator;
3545
3616
 
3546
3617
  /// === IntoIterator ===
3547
- IntoIterator :: (fn(
3548
- comptime(Item) : Type,
3549
- comptime(IntoIter) : Type,
3550
- where(IntoIter <: Iterator(Item))) -> comptime(Trait)) {
3551
- return trait(
3552
- Item := Item,
3553
- IntoIter := IntoIter,
3554
- into_iter :
3555
- fn(self : Self) -> Self.IntoIter
3556
- );
3557
- };
3618
+ IntoIterator :: trait(
3619
+ Item : Type,
3620
+ IntoIter : Type,
3621
+ into_iter :
3622
+ fn(self : Self) -> Self.IntoIter,
3623
+ where(Self.IntoIter <: Iterator(Item := Self.Item))
3624
+ );
3558
3625
  export IntoIterator;
3559
3626
 
3627
+ /// === Array Iterator ===
3628
+ /**
3629
+ * Pointer iterator for Array(T, N) - yields *(T) pointers to each element
3630
+ * Used by Array.iter()
3631
+ */
3632
+ ArrayIterPtr :: (fn(comptime(T) : Type) -> comptime(Type))(
3633
+ struct(
3634
+ _ptr : *(T),
3635
+ _index : usize,
3636
+ _len : usize
3637
+ )
3638
+ );
3639
+
3640
+ impl(forall(T : Type), ArrayIterPtr(T), Iterator(
3641
+ Item : *(T),
3642
+ next : (fn(self : *(Self)) -> Option(*(T)))(
3643
+ cond(
3644
+ (self._index >= self._len) => .None,
3645
+ true => {
3646
+ element_ptr := (self._ptr &+ self._index);
3647
+ self._index = (self._index + usize(1));
3648
+ .Some(element_ptr)
3649
+ }
3650
+ )
3651
+ )
3652
+ ));
3653
+
3654
+ impl(forall(T : Type, N : usize), Array(T, N),
3655
+ iter : (fn(self : *(Self)) -> ArrayIterPtr(T))(
3656
+ ArrayIterPtr(T)(_ptr: &((self.*)(usize(0))), _index: usize(0), _len: N)
3657
+ )
3658
+ );
3659
+
3660
+ export ArrayIterPtr;
3661
+
3662
+ /// === Slice Iterator ===
3663
+ /**
3664
+ * Pointer iterator for Slice(T) - yields *(T) pointers to each element
3665
+ * Used by Slice.iter()
3666
+ */
3667
+ SliceIterPtr :: (fn(comptime(T) : Type) -> comptime(Type))(
3668
+ struct(
3669
+ _slice : Slice(T),
3670
+ _index : usize
3671
+ )
3672
+ );
3673
+
3674
+ impl(forall(T : Type), SliceIterPtr(T), Iterator(
3675
+ Item : *(T),
3676
+ next : (fn(self : *(Self)) -> Option(*(T)))(
3677
+ cond(
3678
+ (self._index >= self._slice.len()) => .None,
3679
+ true => {
3680
+ ptr := &((self._slice)(self._index));
3681
+ self._index = (self._index + usize(1));
3682
+ .Some(ptr)
3683
+ }
3684
+ )
3685
+ )
3686
+ ));
3687
+
3688
+ impl(forall(T : Type), Slice(T),
3689
+ iter : (fn(self : *(Self)) -> SliceIterPtr(T))(
3690
+ SliceIterPtr(T)(_slice: self.*, _index: usize(0))
3691
+ )
3692
+ );
3693
+
3694
+ export SliceIterPtr;
3695
+
3560
3696
  // === Conversion ===
3561
3697
  TryFrom :: (fn(comptime(From) : Type) -> comptime(Trait))(
3562
3698
  trait(
@@ -157,6 +157,17 @@ impl(String,
157
157
  // return self._bytes;
158
158
  // }),
159
159
 
160
+ /**
161
+ * Get a str view into the string's UTF-8 bytes
162
+ * Returns a fat pointer (pointer + length) without copying
163
+ */
164
+ as_str : (fn(self: Self) -> str)(
165
+ match(self._bytes._ptr,
166
+ .Some(p) => str.from_raw_parts(p, self._bytes._length),
167
+ .None => str.from_raw_parts(*(u8)(""), usize(0))
168
+ )
169
+ ),
170
+
160
171
  /**
161
172
  * Decode a UTF-8 encoded rune starting at the given byte index
162
173
  * Internal helper method
@@ -1345,7 +1356,94 @@ impl(String, Eq(String)(
1345
1356
  })
1346
1357
  ));
1347
1358
 
1359
+ // === Iterator support ===
1360
+
1361
+ /**
1362
+ * Rune iterator for String - yields decoded Unicode runes
1363
+ * Used by chars() and into_iter()
1364
+ */
1365
+ StringChars :: struct(
1366
+ _string : String,
1367
+ _byte_index : usize
1368
+ );
1369
+
1370
+ impl(StringChars, Iterator(
1371
+ Item : rune,
1372
+ next : (fn(self : *(Self)) -> Option(rune))(
1373
+ cond(
1374
+ (self._byte_index >= self._string._bytes.len()) => .None,
1375
+ true => {
1376
+ first_byte_opt := self._string._bytes.get(self._byte_index);
1377
+ match(first_byte_opt,
1378
+ .Some(first_byte) => {
1379
+ // Determine byte length of this UTF-8 character
1380
+ (byte_len : usize) = cond(
1381
+ (first_byte < u8(0x80)) => usize(1),
1382
+ ((first_byte >= u8(0xC0)) && (first_byte < u8(0xE0))) => usize(2),
1383
+ ((first_byte >= u8(0xE0)) && (first_byte < u8(0xF0))) => usize(3),
1384
+ ((first_byte >= u8(0xF0)) && (first_byte < u8(0xF8))) => usize(4),
1385
+ true => usize(1)
1386
+ );
1387
+ r := self._string._decode_rune_at(self._byte_index);
1388
+ self._byte_index = (self._byte_index + byte_len);
1389
+ r
1390
+ },
1391
+ .None => .None
1392
+ )
1393
+ }
1394
+ )
1395
+ )
1396
+ ));
1397
+
1398
+ /**
1399
+ * Byte iterator for String - yields raw UTF-8 bytes
1400
+ * Used by bytes()
1401
+ */
1402
+ StringBytes :: struct(
1403
+ _string : String,
1404
+ _index : usize
1405
+ );
1406
+
1407
+ impl(StringBytes, Iterator(
1408
+ Item : u8,
1409
+ next : (fn(self : *(Self)) -> Option(u8))(
1410
+ cond(
1411
+ (self._index >= self._string._bytes.len()) => .None,
1412
+ true => {
1413
+ byte_opt := self._string._bytes.get(self._index);
1414
+ self._index = (self._index + usize(1));
1415
+ byte_opt
1416
+ }
1417
+ )
1418
+ )
1419
+ ));
1420
+
1421
+ impl(String,
1422
+ /**
1423
+ * Returns a rune iterator over the string's Unicode characters
1424
+ */
1425
+ chars : (fn(self : Self) -> StringChars)(
1426
+ StringChars(_string: self, _byte_index: usize(0))
1427
+ ),
1428
+
1429
+ /**
1430
+ * Returns a byte iterator over the string's raw UTF-8 bytes
1431
+ */
1432
+ bytes : (fn(self : Self) -> StringBytes)(
1433
+ StringBytes(_string: self, _index: usize(0))
1434
+ ),
1435
+
1436
+ /**
1437
+ * Consume the string and return a rune iterator (default iteration)
1438
+ */
1439
+ into_iter : (fn(self : Self) -> StringChars)(
1440
+ StringChars(_string: self, _byte_index: usize(0))
1441
+ )
1442
+ );
1443
+
1348
1444
  export
1349
1445
  String,
1350
- StringError
1446
+ StringError,
1447
+ StringChars,
1448
+ StringBytes
1351
1449
  ;
package/std/sync/once.yo CHANGED
@@ -39,7 +39,7 @@ impl(Once,
39
39
  // Note: The fast-path read of _done is not strictly atomic, but since _done
40
40
  // is only ever set from false to true and the double-check inside the lock
41
41
  // prevents the function from running twice, this is safe in practice.
42
- call : (fn(self: Self, f: Fn(() -> unit)) -> unit)({
42
+ call : (fn(self: Self, f: Impl(Fn() -> unit)) -> unit)({
43
43
  // Fast path: already done
44
44
  cond(
45
45
  self._done => (),
@@ -1,4 +1,4 @@
1
- // std/io/advise.yo - Kernel advisory hints
1
+ // std/sys/advise.yo - Kernel advisory hints
2
2
  //
3
3
  // Advisory wrappers for file and memory access pattern hints.
4
4
  // Returns 0 on success, -errno / negative platform error on failure.