feat: lifetime elision, tooling CI, registry, and LSP locals
Ship the QUALITY_PLAN stretch from ownership through ecosystem: C.1 lifetime elision (bootstrap + selfhost), bux fmt/test/doc CI hooks, stdlib goldens, package registry (bux search/add), and LSP 0.4 position-sensitive locals with inferred let types. Full-tree format pass plus Map/Set remove double-free fix.
This commit is contained in:
+122
-114
@@ -1,135 +1,143 @@
|
||||
module Std::Array {
|
||||
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_realloc(ptr: *void, size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
extern func bux_bounds_check(index: uint, len: uint);
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_realloc(ptr: *void, size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
extern func bux_bounds_check(index: uint, len: uint);
|
||||
|
||||
struct Array<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
cap: uint,
|
||||
}
|
||||
/// Growable contiguous buffer of `T` (len + capacity).
|
||||
struct Array<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
cap: uint,
|
||||
}
|
||||
|
||||
func Array_New<T>(cap: uint) -> Array<T> {
|
||||
let data = bux_alloc(cap * sizeof(T)) as *T;
|
||||
return Array<T> { data: data, len: 0, cap: cap };
|
||||
}
|
||||
/// Create an empty array with the given initial capacity.
|
||||
func Array_New<T>(cap: uint) -> Array<T> {
|
||||
let data = bux_alloc(cap * sizeof(T)) as *T;
|
||||
return Array<T> { data: data, len: 0, cap: cap };
|
||||
}
|
||||
|
||||
func Array_Push<T>(self: *Array<T>, value: T) {
|
||||
if self.len >= self.cap {
|
||||
self.cap = self.cap * 2;
|
||||
/// Append `value`, growing capacity if needed.
|
||||
func Array_Push<T>(self: *Array<T>, value: T) {
|
||||
if self.len >= self.cap {
|
||||
self.cap = self.cap * 2;
|
||||
self.data = bux_realloc(self.data as *void, self.cap * sizeof(T)) as *T;
|
||||
}
|
||||
self.data[self.len] = value;
|
||||
self.len = self.len + 1;
|
||||
}
|
||||
|
||||
/// Element at `index` (bounds-checked unless `@[Release]`).
|
||||
func Array_Get<T>(self: *Array<T>, index: uint) -> T {
|
||||
bux_bounds_check(index, self.len);
|
||||
return self.data[index];
|
||||
}
|
||||
|
||||
/// Write `value` at `index` (bounds-checked unless `@[Release]`).
|
||||
func Array_Set<T>(self: *Array<T>, index: uint, value: T) {
|
||||
bux_bounds_check(index, self.len);
|
||||
self.data[index] = value;
|
||||
}
|
||||
|
||||
/// Number of live elements.
|
||||
func Array_Len<T>(self: *Array<T>) -> uint {
|
||||
return self.len;
|
||||
}
|
||||
|
||||
/// Free the backing buffer and reset length/capacity to zero.
|
||||
func Array_Free<T>(self: *Array<T>) {
|
||||
bux_free(self.data as *void);
|
||||
self.data = null as *T;
|
||||
self.len = 0;
|
||||
self.cap = 0;
|
||||
}
|
||||
|
||||
/// Drop trait entry — same as `Array_Free`.
|
||||
func Array_Drop<T>(self: *Array<T>) {
|
||||
Array_Free<T>(self);
|
||||
}
|
||||
|
||||
func Array_operator_index_get<T>(self: *Array<T>, idx: uint) -> T {
|
||||
return Array_Get<T>(self, idx);
|
||||
}
|
||||
|
||||
func Array_operator_index_set<T>(self: *Array<T>, idx: uint, value: T) {
|
||||
Array_Set<T>(self, idx, value);
|
||||
}
|
||||
|
||||
/// True if the array has no elements.
|
||||
func Array_IsEmpty<T>(self: *Array<T>) -> bool {
|
||||
return self.len == 0;
|
||||
}
|
||||
|
||||
/// Current capacity (not length).
|
||||
func Array_Cap<T>(self: *Array<T>) -> uint {
|
||||
return self.cap;
|
||||
}
|
||||
|
||||
/// Drop length to zero; keeps allocated capacity.
|
||||
func Array_Clear<T>(self: *Array<T>) {
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
/// Ensure capacity is at least `minCap` (does not shrink).
|
||||
func Array_Reserve<T>(self: *Array<T>, minCap: uint) {
|
||||
if minCap <= self.cap {
|
||||
return;
|
||||
}
|
||||
self.cap = minCap;
|
||||
self.data = bux_realloc(self.data as *void, self.cap * sizeof(T)) as *T;
|
||||
}
|
||||
self.data[self.len] = value;
|
||||
self.len = self.len + 1;
|
||||
}
|
||||
|
||||
func Array_Get<T>(self: *Array<T>, index: uint) -> T {
|
||||
bux_bounds_check(index, self.len);
|
||||
return self.data[index];
|
||||
}
|
||||
|
||||
func Array_Set<T>(self: *Array<T>, index: uint, value: T) {
|
||||
bux_bounds_check(index, self.len);
|
||||
self.data[index] = value;
|
||||
}
|
||||
|
||||
func Array_Len<T>(self: *Array<T>) -> uint {
|
||||
return self.len;
|
||||
}
|
||||
|
||||
func Array_Free<T>(self: *Array<T>) {
|
||||
bux_free(self.data as *void);
|
||||
self.data = null as *T;
|
||||
self.len = 0;
|
||||
self.cap = 0;
|
||||
}
|
||||
|
||||
func Array_Drop<T>(self: *Array<T>) {
|
||||
Array_Free<T>(self);
|
||||
}
|
||||
|
||||
func Array_operator_index_get<T>(self: *Array<T>, idx: uint) -> T {
|
||||
return Array_Get<T>(self, idx);
|
||||
}
|
||||
|
||||
func Array_operator_index_set<T>(self: *Array<T>, idx: uint, value: T) {
|
||||
Array_Set<T>(self, idx, value);
|
||||
}
|
||||
|
||||
/* True if the array has no elements */
|
||||
func Array_IsEmpty<T>(self: *Array<T>) -> bool {
|
||||
return self.len == 0;
|
||||
}
|
||||
|
||||
/* Current capacity (not length) */
|
||||
func Array_Cap<T>(self: *Array<T>) -> uint {
|
||||
return self.cap;
|
||||
}
|
||||
|
||||
/* Drop length to zero; keeps allocated capacity */
|
||||
func Array_Clear<T>(self: *Array<T>) {
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
/* Ensure capacity is at least minCap (does not shrink) */
|
||||
func Array_Reserve<T>(self: *Array<T>, minCap: uint) {
|
||||
if minCap <= self.cap {
|
||||
return;
|
||||
/// First element (bounds-checked if empty).
|
||||
func Array_First<T>(self: *Array<T>) -> T {
|
||||
return Array_Get<T>(self, 0);
|
||||
}
|
||||
self.cap = minCap;
|
||||
self.data = bux_realloc(self.data as *void, self.cap * sizeof(T)) as *T;
|
||||
}
|
||||
|
||||
/* First element (panics if empty via bounds check) */
|
||||
func Array_First<T>(self: *Array<T>) -> T {
|
||||
return Array_Get<T>(self, 0);
|
||||
}
|
||||
/// Last element (bounds-checked if empty).
|
||||
func Array_Last<T>(self: *Array<T>) -> T {
|
||||
return Array_Get<T>(self, self.len - 1);
|
||||
}
|
||||
|
||||
/* Last element (panics if empty via bounds check) */
|
||||
func Array_Last<T>(self: *Array<T>) -> T {
|
||||
return Array_Get<T>(self, self.len - 1);
|
||||
}
|
||||
/// Remove and return the last element (bounds-checked if empty).
|
||||
func Array_Pop<T>(self: *Array<T>) -> T {
|
||||
bux_bounds_check(0, self.len);
|
||||
self.len = self.len - 1;
|
||||
return self.data[self.len];
|
||||
}
|
||||
|
||||
/* Remove and return the last element (panics if empty) */
|
||||
func Array_Pop<T>(self: *Array<T>) -> T {
|
||||
bux_bounds_check(0, self.len);
|
||||
self.len = self.len - 1;
|
||||
return self.data[self.len];
|
||||
}
|
||||
|
||||
/* Linear search: true if value is present (uses ==) */
|
||||
func Array_Contains<T>(self: *Array<T>, value: T) -> bool {
|
||||
var i: uint = 0;
|
||||
while i < self.len {
|
||||
if self.data[i] == value {
|
||||
return true;
|
||||
/// Linear search: true if `value` is present (uses `==`).
|
||||
func Array_Contains<T>(self: *Array<T>, value: T) -> bool {
|
||||
var i: uint = 0;
|
||||
while i < self.len {
|
||||
if self.data[i] == value {
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Index of first equal element, or -1 if not found */
|
||||
func Array_IndexOf<T>(self: *Array<T>, value: T) -> int {
|
||||
var i: uint = 0;
|
||||
while i < self.len {
|
||||
if self.data[i] == value {
|
||||
return i as int;
|
||||
/// Index of first equal element, or `-1` if not found.
|
||||
func Array_IndexOf<T>(self: *Array<T>, value: T) -> int {
|
||||
var i: uint = 0;
|
||||
while i < self.len {
|
||||
if self.data[i] == value {
|
||||
return i as int;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Append all elements of other onto self */
|
||||
func Array_Extend<T>(self: *Array<T>, other: *Array<T>) {
|
||||
var i: uint = 0;
|
||||
while i < other.len {
|
||||
Array_Push<T>(self, other.data[i]);
|
||||
i = i + 1;
|
||||
/// Append all elements of `other` onto `self`.
|
||||
func Array_Extend<T>(self: *Array<T>, other: *Array<T>) {
|
||||
var i: uint = 0;
|
||||
while i < other.len {
|
||||
Array_Push<T>(self, other.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+48
-48
@@ -1,64 +1,64 @@
|
||||
module Std::Channel {
|
||||
|
||||
extern func bux_channel_new(capacity: int64, elem_size: int64) -> *void;
|
||||
extern func bux_channel_send(handle: *void, elem: *void);
|
||||
extern func bux_channel_recv(handle: *void, out: *void) -> int;
|
||||
extern func bux_channel_close(handle: *void);
|
||||
extern func bux_channel_free(handle: *void);
|
||||
extern func bux_channel_new(capacity: int64, elem_size: int64) -> *void;
|
||||
extern func bux_channel_send(handle: *void, elem: *void);
|
||||
extern func bux_channel_recv(handle: *void, out: *void) -> int;
|
||||
extern func bux_channel_close(handle: *void);
|
||||
extern func bux_channel_free(handle: *void);
|
||||
|
||||
struct Channel<T> {
|
||||
handle: *void;
|
||||
}
|
||||
struct Channel<T> {
|
||||
handle: *void;
|
||||
}
|
||||
|
||||
func Channel_New<T>(capacity: int64) -> Channel<T> {
|
||||
return Channel<T> { handle: bux_channel_new(capacity, sizeof(T)) };
|
||||
}
|
||||
func Channel_New<T>(capacity: int64) -> Channel<T> {
|
||||
return Channel<T> { handle: bux_channel_new(capacity, sizeof(T)) };
|
||||
}
|
||||
|
||||
func Channel_Send<T>(ch: *Channel<T>, value: T) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
func Channel_Send<T>(ch: *Channel<T>, value: T) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
|
||||
func Channel_Recv<T>(ch: *Channel<T>) -> T {
|
||||
var result: T;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
func Channel_Recv<T>(ch: *Channel<T>) -> T {
|
||||
var result: T;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Channel_Recv_Ok<T>(ch: *Channel<T>, out: *T) -> bool {
|
||||
return bux_channel_recv(ch.handle, out as *void) != 0;
|
||||
}
|
||||
func Channel_Recv_Ok<T>(ch: *Channel<T>, out: *T) -> bool {
|
||||
return bux_channel_recv(ch.handle, out as *void) != 0;
|
||||
}
|
||||
|
||||
func Channel_Close<T>(ch: *Channel<T>) {
|
||||
bux_channel_close(ch.handle);
|
||||
}
|
||||
func Channel_Close<T>(ch: *Channel<T>) {
|
||||
bux_channel_close(ch.handle);
|
||||
}
|
||||
|
||||
func Channel_Free<T>(ch: *Channel<T>) {
|
||||
bux_channel_free(ch.handle);
|
||||
}
|
||||
func Channel_Free<T>(ch: *Channel<T>) {
|
||||
bux_channel_free(ch.handle);
|
||||
}
|
||||
|
||||
func Channel_Drop<T>(ch: *Channel<T>) {
|
||||
Channel_Free<T>(ch);
|
||||
}
|
||||
func Channel_Drop<T>(ch: *Channel<T>) {
|
||||
Channel_Free<T>(ch);
|
||||
}
|
||||
|
||||
/* Convenience wrappers for common types */
|
||||
func Channel_SendInt(ch: *Channel<int>, value: int) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
/* Convenience wrappers for common types */
|
||||
func Channel_SendInt(ch: *Channel<int>, value: int) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
|
||||
func Channel_RecvInt(ch: *Channel<int>) -> int {
|
||||
var result: int = 0;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
func Channel_RecvInt(ch: *Channel<int>) -> int {
|
||||
var result: int = 0;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Channel_SendFloat64(ch: *Channel<float64>, value: float64) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
func Channel_SendFloat64(ch: *Channel<float64>, value: float64) {
|
||||
bux_channel_send(ch.handle, (&value) as *void);
|
||||
}
|
||||
|
||||
func Channel_RecvFloat64(ch: *Channel<float64>) -> float64 {
|
||||
var result: float64 = 0.0;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
func Channel_RecvFloat64(ch: *Channel<float64>) -> float64 {
|
||||
var result: float64 = 0.0;
|
||||
bux_channel_recv(ch.handle, (&result) as *void);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+61
-61
@@ -10,72 +10,72 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
// Re-use the same externs from submodules (merged by compiler)
|
||||
extern func bux_sha256(data: String, len: int, out: *void);
|
||||
extern func bux_hmac_sha256(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
// Re-use the same externs from submodules (merged by compiler)
|
||||
extern func bux_sha256(data: String, len: int, out: *void);
|
||||
extern func bux_hmac_sha256(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
|
||||
// --- Legacy function names (delegate to new submodule functions) ---
|
||||
// --- Legacy function names (delegate to new submodule functions) ---
|
||||
|
||||
// SHA-256 → hex
|
||||
func Crypto_Sha256(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let hashBuf: *void = Alloc(32);
|
||||
bux_sha256(data, len, hashBuf);
|
||||
let result: String = bux_bytes_to_hex(hashBuf as *void, 32);
|
||||
Free(hashBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// HMAC-SHA256 → hex
|
||||
func Crypto_HmacSha256(key: String, message: String) -> String {
|
||||
let keylen: int = String_Len(key) as int;
|
||||
let msglen: int = String_Len(message) as int;
|
||||
let hmacBuf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
|
||||
let result: String = bux_bytes_to_hex(hmacBuf as *void, 32);
|
||||
Free(hmacBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Random bytes → base64
|
||||
func Crypto_RandomBytes(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
// SHA-256 → hex
|
||||
func Crypto_Sha256(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let hashBuf: *void = Alloc(32);
|
||||
bux_sha256(data, len, hashBuf);
|
||||
let result: String = bux_bytes_to_hex(hashBuf as *void, 32);
|
||||
Free(hashBuf);
|
||||
return result;
|
||||
}
|
||||
let result: String = bux_base64_encode(buf as String, n);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Base64 encode
|
||||
func Crypto_Base64Encode(s: String) -> String {
|
||||
return bux_base64_encode(s, String_Len(s) as int);
|
||||
}
|
||||
// HMAC-SHA256 → hex
|
||||
func Crypto_HmacSha256(key: String, message: String) -> String {
|
||||
let keylen: int = String_Len(key) as int;
|
||||
let msglen: int = String_Len(message) as int;
|
||||
let hmacBuf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
|
||||
let result: String = bux_bytes_to_hex(hmacBuf as *void, 32);
|
||||
Free(hmacBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// HMAC-SHA256 raw → base64
|
||||
func Crypto_HmacSha256Raw(key: String, message: String) -> String {
|
||||
let keylen: int = String_Len(key) as int;
|
||||
let msglen: int = String_Len(message) as int;
|
||||
let hmacBuf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
|
||||
let result: String = bux_base64_encode(hmacBuf as String, 32);
|
||||
Free(hmacBuf);
|
||||
return result;
|
||||
}
|
||||
// Random bytes → base64
|
||||
func Crypto_RandomBytes(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
let result: String = bux_base64_encode(buf as String, n);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Base64 decode
|
||||
func Crypto_Base64Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
// Base64 encode
|
||||
func Crypto_Base64Encode(s: String) -> String {
|
||||
return bux_base64_encode(s, String_Len(s) as int);
|
||||
}
|
||||
|
||||
// HMAC-SHA256 raw → base64
|
||||
func Crypto_HmacSha256Raw(key: String, message: String) -> String {
|
||||
let keylen: int = String_Len(key) as int;
|
||||
let msglen: int = String_Len(message) as int;
|
||||
let hmacBuf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
|
||||
let result: String = bux_base64_encode(hmacBuf as String, 32);
|
||||
Free(hmacBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Base64 decode
|
||||
func Crypto_Base64Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
}
|
||||
|
||||
+74
-74
@@ -8,93 +8,93 @@
|
||||
|
||||
module Std::Fmt {
|
||||
|
||||
import Std::String::{
|
||||
String_Eq,
|
||||
String_FromInt,
|
||||
String_FromFloat,
|
||||
String_FromBool,
|
||||
StringBuilder,
|
||||
StringBuilder_New,
|
||||
StringBuilder_Append,
|
||||
StringBuilder_Build,
|
||||
String_Chars
|
||||
};
|
||||
import Std::String::{
|
||||
String_Eq,
|
||||
String_FromInt,
|
||||
String_FromFloat,
|
||||
String_FromBool,
|
||||
StringBuilder,
|
||||
StringBuilder_New,
|
||||
StringBuilder_Append,
|
||||
StringBuilder_Build,
|
||||
String_Chars
|
||||
};
|
||||
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_str_to_int(s: String) -> int64;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_str_to_int(s: String) -> int64;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
|
||||
// Core formatting engine: replace {0}..{9} in template with args
|
||||
func Fmt_Format(tmpl: String, argStrs: *String, argCount: int) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
var i: uint = 0;
|
||||
let tmplLen: uint = bux_strlen(tmpl);
|
||||
while i < tmplLen {
|
||||
// Check for {
|
||||
let ch: String = String_Chars(tmpl, i);
|
||||
if String_Eq(ch, "{") {
|
||||
let digitIdx: uint = i + 1;
|
||||
if digitIdx < tmplLen {
|
||||
let digitCh: String = String_Chars(tmpl, digitIdx);
|
||||
let d: int64 = bux_str_to_int(digitCh);
|
||||
if d >= 0 && d < argCount as int64 {
|
||||
// Consume {d}
|
||||
i = i + 2; // skip past digit
|
||||
// Check for closing }
|
||||
if i < tmplLen {
|
||||
let closeCh: String = String_Chars(tmpl, i);
|
||||
if String_Eq(closeCh, "}") {
|
||||
i = i + 1; // skip }
|
||||
let argStr: String = argStrs[d as uint];
|
||||
StringBuilder_Append(&sb, argStr);
|
||||
continue;
|
||||
// Core formatting engine: replace {0}..{9} in template with args
|
||||
func Fmt_Format(tmpl: String, argStrs: *String, argCount: int) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
var i: uint = 0;
|
||||
let tmplLen: uint = bux_strlen(tmpl);
|
||||
while i < tmplLen {
|
||||
// Check for {
|
||||
let ch: String = String_Chars(tmpl, i);
|
||||
if String_Eq(ch, "{") {
|
||||
let digitIdx: uint = i + 1;
|
||||
if digitIdx < tmplLen {
|
||||
let digitCh: String = String_Chars(tmpl, digitIdx);
|
||||
let d: int64 = bux_str_to_int(digitCh);
|
||||
if d >= 0 && d < argCount as int64 {
|
||||
// Consume {d}
|
||||
i = i + 2; // skip past digit
|
||||
// Check for closing }
|
||||
if i < tmplLen {
|
||||
let closeCh: String = String_Chars(tmpl, i);
|
||||
if String_Eq(closeCh, "}") {
|
||||
i = i + 1; // skip }
|
||||
let argStr: String = argStrs[d as uint];
|
||||
StringBuilder_Append(&sb, argStr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Normal character: append it
|
||||
StringBuilder_Append(&sb, ch);
|
||||
i = i + 1;
|
||||
}
|
||||
// Normal character: append it
|
||||
StringBuilder_Append(&sb, ch);
|
||||
i = i + 1;
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
|
||||
// Convenience wrappers
|
||||
func Fmt_Fmt1(tmpl: String, a1: String) -> String {
|
||||
var args: *String = bux_alloc(sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
return Fmt_Format(tmpl, args, 1);
|
||||
}
|
||||
// Convenience wrappers
|
||||
func Fmt_Fmt1(tmpl: String, a1: String) -> String {
|
||||
var args: *String = bux_alloc(sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
return Fmt_Format(tmpl, args, 1);
|
||||
}
|
||||
|
||||
func Fmt_FmtInt(tmpl: String, val: int64) -> String {
|
||||
let s: String = String_FromInt(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
func Fmt_FmtInt(tmpl: String, val: int64) -> String {
|
||||
let s: String = String_FromInt(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
|
||||
func Fmt_FmtBool(tmpl: String, val: bool) -> String {
|
||||
let s: String = String_FromBool(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
func Fmt_FmtBool(tmpl: String, val: bool) -> String {
|
||||
let s: String = String_FromBool(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
|
||||
func Fmt_FmtFloat(tmpl: String, val: float64) -> String {
|
||||
let s: String = String_FromFloat(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
func Fmt_FmtFloat(tmpl: String, val: float64) -> String {
|
||||
let s: String = String_FromFloat(val);
|
||||
return Fmt_Fmt1(tmpl, s);
|
||||
}
|
||||
|
||||
func Fmt_Fmt2(tmpl: String, a1: String, a2: String) -> String {
|
||||
var args: *String = bux_alloc(2 * sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
args[1] = a2;
|
||||
return Fmt_Format(tmpl, args, 2);
|
||||
}
|
||||
func Fmt_Fmt2(tmpl: String, a1: String, a2: String) -> String {
|
||||
var args: *String = bux_alloc(2 * sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
args[1] = a2;
|
||||
return Fmt_Format(tmpl, args, 2);
|
||||
}
|
||||
|
||||
func Fmt_Fmt3(tmpl: String, a1: String, a2: String, a3: String) -> String {
|
||||
var args: *String = bux_alloc(3 * sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
args[1] = a2;
|
||||
args[2] = a3;
|
||||
return Fmt_Format(tmpl, args, 3);
|
||||
}
|
||||
func Fmt_Fmt3(tmpl: String, a1: String, a2: String, a3: String) -> String {
|
||||
var args: *String = bux_alloc(3 * sizeof(String)) as *String;
|
||||
args[0] = a1;
|
||||
args[1] = a2;
|
||||
args[2] = a3;
|
||||
return Fmt_Format(tmpl, args, 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,19 +1,19 @@
|
||||
module Std::Fs {
|
||||
|
||||
extern func bux_dir_exists(path: String) -> int;
|
||||
extern func bux_mkdir_if_needed(path: String) -> int;
|
||||
extern func bux_list_dir(dir: String, ext: String, out_count: *int) -> *String;
|
||||
extern func bux_dir_exists(path: String) -> int;
|
||||
extern func bux_mkdir_if_needed(path: String) -> int;
|
||||
extern func bux_list_dir(dir: String, ext: String, out_count: *int) -> *String;
|
||||
|
||||
func DirExists(path: String) -> bool {
|
||||
return bux_dir_exists(path) != 0;
|
||||
}
|
||||
func DirExists(path: String) -> bool {
|
||||
return bux_dir_exists(path) != 0;
|
||||
}
|
||||
|
||||
func Mkdir(path: String) -> bool {
|
||||
return bux_mkdir_if_needed(path) != 0;
|
||||
}
|
||||
func Mkdir(path: String) -> bool {
|
||||
return bux_mkdir_if_needed(path) != 0;
|
||||
}
|
||||
|
||||
func ListDir(dir: String, ext: String, count: *int) -> *String {
|
||||
return bux_list_dir(dir, ext, count);
|
||||
}
|
||||
func ListDir(dir: String, ext: String, count: *int) -> *String {
|
||||
return bux_list_dir(dir, ext, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-21
@@ -1,28 +1,28 @@
|
||||
module Std::Io {
|
||||
|
||||
extern func PrintLine(s: String);
|
||||
extern func Print(s: String);
|
||||
extern func PrintInt(n: int);
|
||||
extern func PrintInt64(n: int64);
|
||||
extern func PrintFloat(f: float64);
|
||||
extern func PrintBool(b: bool);
|
||||
extern func ReadLine() -> String;
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> int;
|
||||
extern func bux_file_exists(path: String) -> int;
|
||||
extern func PrintLine(s: String);
|
||||
extern func Print(s: String);
|
||||
extern func PrintInt(n: int);
|
||||
extern func PrintInt64(n: int64);
|
||||
extern func PrintFloat(f: float64);
|
||||
extern func PrintBool(b: bool);
|
||||
extern func ReadLine() -> String;
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> int;
|
||||
extern func bux_file_exists(path: String) -> int;
|
||||
|
||||
func ReadFile(path: String) -> String {
|
||||
return bux_read_file(path);
|
||||
}
|
||||
func ReadFile(path: String) -> String {
|
||||
return bux_read_file(path);
|
||||
}
|
||||
|
||||
func WriteFile(path: String, content: String) -> bool {
|
||||
let r: int = bux_write_file(path, content);
|
||||
return r != 0;
|
||||
}
|
||||
func WriteFile(path: String, content: String) -> bool {
|
||||
let r: int = bux_write_file(path, content);
|
||||
return r != 0;
|
||||
}
|
||||
|
||||
func FileExists(path: String) -> bool {
|
||||
let r: int = bux_file_exists(path);
|
||||
return r != 0;
|
||||
}
|
||||
func FileExists(path: String) -> bool {
|
||||
let r: int = bux_file_exists(path);
|
||||
return r != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+201
-201
@@ -1,233 +1,233 @@
|
||||
module Std::Iter {
|
||||
|
||||
import Std::Array::*;
|
||||
import Std::Array::*;
|
||||
|
||||
struct Iter<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
pos: uint,
|
||||
}
|
||||
|
||||
/* Create an iterator from an Array */
|
||||
func Array_Iter<T>(arr: *Array<T>) -> Iter<T> {
|
||||
return Iter<T> { data: arr.data, len: arr.len, pos: 0 };
|
||||
}
|
||||
|
||||
/* Check if there are more elements */
|
||||
func Iter_HasNext<T>(it: *Iter<T>) -> bool {
|
||||
return it.pos < it.len;
|
||||
}
|
||||
|
||||
/* Get the next element and advance (undefined if HasNext is false) */
|
||||
func Iter_Next<T>(it: *Iter<T>) -> T {
|
||||
let val: T = it.data[it.pos];
|
||||
it.pos = it.pos + 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Peek current element without advancing (undefined if HasNext is false) */
|
||||
func Iter_Peek<T>(it: *Iter<T>) -> T {
|
||||
return it.data[it.pos];
|
||||
}
|
||||
|
||||
/* Reset iterator to the beginning */
|
||||
func Iter_Reset<T>(it: *Iter<T>) {
|
||||
it.pos = 0;
|
||||
}
|
||||
|
||||
/* Current position */
|
||||
func Iter_Pos<T>(it: *Iter<T>) -> uint {
|
||||
return it.pos;
|
||||
}
|
||||
|
||||
/* Remaining length */
|
||||
func Iter_Len<T>(it: *Iter<T>) -> uint {
|
||||
return it.len;
|
||||
}
|
||||
|
||||
/* Count remaining elements */
|
||||
func Iter_Count<T>(it: *Iter<T>) -> uint {
|
||||
return it.len - it.pos;
|
||||
}
|
||||
|
||||
/* Skip N elements */
|
||||
func Iter_Skip<T>(it: *Iter<T>, n: uint) {
|
||||
it.pos = it.pos + n;
|
||||
if it.pos > it.len {
|
||||
it.pos = it.len;
|
||||
struct Iter<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
pos: uint,
|
||||
}
|
||||
}
|
||||
|
||||
/* Take first N elements (by limiting len) */
|
||||
func Iter_Take<T>(it: *Iter<T>, n: uint) -> Iter<T> {
|
||||
var endPos: uint = it.pos + n;
|
||||
if endPos > it.len {
|
||||
endPos = it.len;
|
||||
/* Create an iterator from an Array */
|
||||
func Array_Iter<T>(arr: *Array<T>) -> Iter<T> {
|
||||
return Iter<T> { data: arr.data, len: arr.len, pos: 0 };
|
||||
}
|
||||
return Iter<T> { data: it.data, len: endPos, pos: it.pos };
|
||||
}
|
||||
|
||||
/* True if any remaining element equals value */
|
||||
func Iter_AnyEq<T>(it: *Iter<T>, value: T) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if it.data[i] == value {
|
||||
return true;
|
||||
/* Check if there are more elements */
|
||||
func Iter_HasNext<T>(it: *Iter<T>) -> bool {
|
||||
return it.pos < it.len;
|
||||
}
|
||||
|
||||
/* Get the next element and advance (undefined if HasNext is false) */
|
||||
func Iter_Next<T>(it: *Iter<T>) -> T {
|
||||
let val: T = it.data[it.pos];
|
||||
it.pos = it.pos + 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Peek current element without advancing (undefined if HasNext is false) */
|
||||
func Iter_Peek<T>(it: *Iter<T>) -> T {
|
||||
return it.data[it.pos];
|
||||
}
|
||||
|
||||
/* Reset iterator to the beginning */
|
||||
func Iter_Reset<T>(it: *Iter<T>) {
|
||||
it.pos = 0;
|
||||
}
|
||||
|
||||
/* Current position */
|
||||
func Iter_Pos<T>(it: *Iter<T>) -> uint {
|
||||
return it.pos;
|
||||
}
|
||||
|
||||
/* Remaining length */
|
||||
func Iter_Len<T>(it: *Iter<T>) -> uint {
|
||||
return it.len;
|
||||
}
|
||||
|
||||
/* Count remaining elements */
|
||||
func Iter_Count<T>(it: *Iter<T>) -> uint {
|
||||
return it.len - it.pos;
|
||||
}
|
||||
|
||||
/* Skip N elements */
|
||||
func Iter_Skip<T>(it: *Iter<T>, n: uint) {
|
||||
it.pos = it.pos + n;
|
||||
if it.pos > it.len {
|
||||
it.pos = it.len;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* True if every remaining element equals value (true if empty) */
|
||||
func Iter_AllEq<T>(it: *Iter<T>, value: T) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if it.data[i] != value {
|
||||
return false;
|
||||
/* Take first N elements (by limiting len) */
|
||||
func Iter_Take<T>(it: *Iter<T>, n: uint) -> Iter<T> {
|
||||
var endPos: uint = it.pos + n;
|
||||
if endPos > it.len {
|
||||
endPos = it.len;
|
||||
}
|
||||
i = i + 1;
|
||||
return Iter<T> { data: it.data, len: endPos, pos: it.pos };
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Collect remaining elements into a new Array */
|
||||
func Iter_Collect<T>(it: *Iter<T>) -> Array<T> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
var arr: Array<T> = Array_New<T>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
Array_Push<T>(&arr, it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Higher-order helpers (generic; fat func pointers / closures)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Map each remaining element through f: T → U, collect into Array<U> */
|
||||
func Iter_Map<T, U>(it: *Iter<T>, f: func(T) -> U) -> Array<U> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
var out: Array<U> = Array_New<U>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let mapped: U = f(it.data[i]);
|
||||
Array_Push<U>(&out, mapped);
|
||||
i = i + 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Keep remaining elements for which pred returns true */
|
||||
func Iter_Filter<T>(it: *Iter<T>, pred: func(T) -> bool) -> Array<T> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
var out: Array<T> = Array_New<T>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let v: T = it.data[i];
|
||||
if pred(v) {
|
||||
Array_Push<T>(&out, v);
|
||||
/* True if any remaining element equals value */
|
||||
func Iter_AnyEq<T>(it: *Iter<T>, value: T) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if it.data[i] == value {
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Left-fold: f(f(...f(init, x0), x1), ...) */
|
||||
func Iter_Fold<T, Acc>(it: *Iter<T>, init: Acc, f: func(Acc, T) -> Acc) -> Acc {
|
||||
var acc: Acc = init;
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
acc = f(acc, it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
/* Call f for each remaining element (return value of f is ignored) */
|
||||
func Iter_ForEach<T>(it: *Iter<T>, f: func(T) -> int) {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let _ignored: int = f(it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* True if any remaining element satisfies pred */
|
||||
func Iter_Any<T>(it: *Iter<T>, pred: func(T) -> bool) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if pred(it.data[i]) {
|
||||
return true;
|
||||
/* True if every remaining element equals value (true if empty) */
|
||||
func Iter_AllEq<T>(it: *Iter<T>, value: T) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if it.data[i] != value {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* True if all remaining elements satisfy pred (true if empty) */
|
||||
func Iter_All<T>(it: *Iter<T>, pred: func(T) -> bool) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if !pred(it.data[i]) {
|
||||
return false;
|
||||
/* Collect remaining elements into a new Array */
|
||||
func Iter_Collect<T>(it: *Iter<T>) -> Array<T> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
i = i + 1;
|
||||
var arr: Array<T> = Array_New<T>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
Array_Push<T>(&arr, it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Sum remaining ints (specialized fold) */
|
||||
func Iter_SumInt(it: *Iter<int>) -> int {
|
||||
var total: int = 0;
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
total = total + it.data[i];
|
||||
i = i + 1;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Higher-order helpers (generic; fat func pointers / closures)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Map each remaining element through f: T → U, collect into Array<U> */
|
||||
func Iter_Map<T, U>(it: *Iter<T>, f: func(T) -> U) -> Array<U> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
var out: Array<U> = Array_New<U>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let mapped: U = f(it.data[i]);
|
||||
Array_Push<U>(&out, mapped);
|
||||
i = i + 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Int-specialized aliases (backward compatible with earlier examples)
|
||||
// ---------------------------------------------------------------------------
|
||||
/* Keep remaining elements for which pred returns true */
|
||||
func Iter_Filter<T>(it: *Iter<T>, pred: func(T) -> bool) -> Array<T> {
|
||||
let remaining: uint = it.len - it.pos;
|
||||
var cap: uint = remaining;
|
||||
if cap == 0 {
|
||||
cap = 1;
|
||||
}
|
||||
var out: Array<T> = Array_New<T>(cap);
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let v: T = it.data[i];
|
||||
if pred(v) {
|
||||
Array_Push<T>(&out, v);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
func Iter_MapInt(it: *Iter<int>, f: func(int) -> int) -> Array<int> {
|
||||
return Iter_Map<int, int>(it, f);
|
||||
}
|
||||
/* Left-fold: f(f(...f(init, x0), x1), ...) */
|
||||
func Iter_Fold<T, Acc>(it: *Iter<T>, init: Acc, f: func(Acc, T) -> Acc) -> Acc {
|
||||
var acc: Acc = init;
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
acc = f(acc, it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
func Iter_FilterInt(it: *Iter<int>, pred: func(int) -> bool) -> Array<int> {
|
||||
return Iter_Filter<int>(it, pred);
|
||||
}
|
||||
/* Call f for each remaining element (return value of f is ignored) */
|
||||
func Iter_ForEach<T>(it: *Iter<T>, f: func(T) -> int) {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
let _ignored: int = f(it.data[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
func Iter_FoldInt(it: *Iter<int>, init: int, f: func(int, int) -> int) -> int {
|
||||
return Iter_Fold<int, int>(it, init, f);
|
||||
}
|
||||
/* True if any remaining element satisfies pred */
|
||||
func Iter_Any<T>(it: *Iter<T>, pred: func(T) -> bool) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if pred(it.data[i]) {
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Iter_ForEachInt(it: *Iter<int>, f: func(int) -> int) {
|
||||
Iter_ForEach<int>(it, f);
|
||||
}
|
||||
/* True if all remaining elements satisfy pred (true if empty) */
|
||||
func Iter_All<T>(it: *Iter<T>, pred: func(T) -> bool) -> bool {
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
if !pred(it.data[i]) {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func Iter_AnyInt(it: *Iter<int>, pred: func(int) -> bool) -> bool {
|
||||
return Iter_Any<int>(it, pred);
|
||||
}
|
||||
/* Sum remaining ints (specialized fold) */
|
||||
func Iter_SumInt(it: *Iter<int>) -> int {
|
||||
var total: int = 0;
|
||||
var i: uint = it.pos;
|
||||
while i < it.len {
|
||||
total = total + it.data[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
func Iter_AllInt(it: *Iter<int>, pred: func(int) -> bool) -> bool {
|
||||
return Iter_All<int>(it, pred);
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// Int-specialized aliases (backward compatible with earlier examples)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Iter_MapInt(it: *Iter<int>, f: func(int) -> int) -> Array<int> {
|
||||
return Iter_Map<int, int>(it, f);
|
||||
}
|
||||
|
||||
func Iter_FilterInt(it: *Iter<int>, pred: func(int) -> bool) -> Array<int> {
|
||||
return Iter_Filter<int>(it, pred);
|
||||
}
|
||||
|
||||
func Iter_FoldInt(it: *Iter<int>, init: int, f: func(int, int) -> int) -> int {
|
||||
return Iter_Fold<int, int>(it, init, f);
|
||||
}
|
||||
|
||||
func Iter_ForEachInt(it: *Iter<int>, f: func(int) -> int) {
|
||||
Iter_ForEach<int>(it, f);
|
||||
}
|
||||
|
||||
func Iter_AnyInt(it: *Iter<int>, pred: func(int) -> bool) -> bool {
|
||||
return Iter_Any<int>(it, pred);
|
||||
}
|
||||
|
||||
func Iter_AllInt(it: *Iter<int>, pred: func(int) -> bool) -> bool {
|
||||
return Iter_All<int>(it, pred);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+408
-408
@@ -1,297 +1,287 @@
|
||||
module Std::Json {
|
||||
import Std::Mem::{Alloc, Realloc, Free};
|
||||
import Std::String;
|
||||
import Std::Mem::{Alloc, Realloc, Free};
|
||||
import Std::String;
|
||||
|
||||
/* === Tags === */
|
||||
const JsonTagNull: int = 0;
|
||||
const JsonTagBool: int = 1;
|
||||
const JsonTagNumber: int = 2;
|
||||
const JsonTagString: int = 3;
|
||||
const JsonTagArray: int = 4;
|
||||
const JsonTagObject: int = 5;
|
||||
/* === Tags === */
|
||||
const JsonTagNull: int = 0;
|
||||
const JsonTagBool: int = 1;
|
||||
const JsonTagNumber: int = 2;
|
||||
const JsonTagString: int = 3;
|
||||
const JsonTagArray: int = 4;
|
||||
const JsonTagObject: int = 5;
|
||||
|
||||
/* === Core type === */
|
||||
struct JsonValue {
|
||||
tag: int,
|
||||
boolVal: bool,
|
||||
numVal: float64,
|
||||
strVal: String,
|
||||
arrData: *JsonValue,
|
||||
arrLen: uint,
|
||||
arrCap: uint,
|
||||
objKeys: *String,
|
||||
objValues: *JsonValue,
|
||||
objLen: uint,
|
||||
objCap: uint
|
||||
}
|
||||
/* === Core type === */
|
||||
struct JsonValue {
|
||||
tag: int,
|
||||
boolVal: bool,
|
||||
numVal: float64,
|
||||
strVal: String,
|
||||
arrData: *JsonValue,
|
||||
arrLen: uint,
|
||||
arrCap: uint,
|
||||
objKeys: *String,
|
||||
objValues: *JsonValue,
|
||||
objLen: uint,
|
||||
objCap: uint
|
||||
}
|
||||
|
||||
/* === Constructors === */
|
||||
func Json_Null() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagNull, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
/* === Constructors === */
|
||||
func Json_Null() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagNull, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
func Json_Bool(b: bool) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagBool, boolVal: b, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
func Json_Bool(b: bool) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagBool, boolVal: b, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
func Json_Number(n: float64) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagNumber, boolVal: false, numVal: n, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
func Json_Number(n: float64) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagNumber, boolVal: false, numVal: n, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
func Json_String(s: String) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagString, boolVal: false, numVal: 0.0, strVal: s,
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
func Json_String(s: String) -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagString, boolVal: false, numVal: 0.0, strVal: s,
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
func Json_Array() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagArray, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
func Json_Array() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagArray, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
func Json_Object() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagObject, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
func Json_Object() -> JsonValue {
|
||||
return JsonValue {
|
||||
tag: JsonTagObject, boolVal: false, numVal: 0.0, strVal: "",
|
||||
arrData: null, arrLen: 0, arrCap: 0,
|
||||
objKeys: null, objValues: null, objLen: 0, objCap: 0
|
||||
};
|
||||
}
|
||||
|
||||
/* === Array helpers === */
|
||||
func Json_ArrayLen(v: JsonValue) -> uint {
|
||||
if v.tag != JsonTagArray { return 0; }
|
||||
return v.arrLen;
|
||||
}
|
||||
/* === Array helpers === */
|
||||
func Json_ArrayLen(v: JsonValue) -> uint {
|
||||
if v.tag != JsonTagArray { return 0; }
|
||||
return v.arrLen;
|
||||
}
|
||||
|
||||
func Json_ArrayGet(v: JsonValue, index: uint) -> JsonValue {
|
||||
if v.tag != JsonTagArray { return Json_Null(); }
|
||||
if index >= v.arrLen { return Json_Null(); }
|
||||
return v.arrData[index];
|
||||
}
|
||||
func Json_ArrayGet(v: JsonValue, index: uint) -> JsonValue {
|
||||
if v.tag != JsonTagArray { return Json_Null(); }
|
||||
if index >= v.arrLen { return Json_Null(); }
|
||||
return v.arrData[index];
|
||||
}
|
||||
|
||||
func Json_ArrayPush(self: *JsonValue, val: JsonValue) {
|
||||
if self.tag != JsonTagArray { return; }
|
||||
if self.arrLen >= self.arrCap {
|
||||
let arrNewCap: uint = self.arrCap;
|
||||
if arrNewCap == 0 {
|
||||
self.arrCap = 4;
|
||||
self.arrData = Alloc(4 * sizeof(JsonValue)) as *JsonValue;
|
||||
} else {
|
||||
let doubleCap: uint = arrNewCap * 2;
|
||||
self.arrCap = doubleCap;
|
||||
self.arrData = Realloc(self.arrData as *void, doubleCap * sizeof(JsonValue)) as *JsonValue;
|
||||
func Json_ArrayPush(self: *JsonValue, val: JsonValue) {
|
||||
if self.tag != JsonTagArray { return; }
|
||||
if self.arrLen >= self.arrCap {
|
||||
let arrNewCap: uint = self.arrCap;
|
||||
if arrNewCap == 0 {
|
||||
self.arrCap = 4;
|
||||
self.arrData = Alloc(4 * sizeof(JsonValue)) as *JsonValue;
|
||||
} else {
|
||||
let doubleCap: uint = arrNewCap * 2;
|
||||
self.arrCap = doubleCap;
|
||||
self.arrData = Realloc(self.arrData as *void, doubleCap * sizeof(JsonValue)) as *JsonValue;
|
||||
}
|
||||
}
|
||||
self.arrData[self.arrLen] = val;
|
||||
self.arrLen = self.arrLen + 1;
|
||||
}
|
||||
self.arrData[self.arrLen] = val;
|
||||
self.arrLen = self.arrLen + 1;
|
||||
}
|
||||
|
||||
/* === Object helpers === */
|
||||
func Json_ObjectLen(v: JsonValue) -> uint {
|
||||
if v.tag != JsonTagObject { return 0; }
|
||||
return v.objLen;
|
||||
}
|
||||
/* === Object helpers === */
|
||||
func Json_ObjectLen(v: JsonValue) -> uint {
|
||||
if v.tag != JsonTagObject { return 0; }
|
||||
return v.objLen;
|
||||
}
|
||||
|
||||
func Json_ObjectGet(v: JsonValue, key: String) -> JsonValue {
|
||||
if v.tag != JsonTagObject { return Json_Null(); }
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if String_Eq(v.objKeys[i], key) {
|
||||
return v.objValues[i];
|
||||
func Json_ObjectGet(v: JsonValue, key: String) -> JsonValue {
|
||||
if v.tag != JsonTagObject { return Json_Null(); }
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if String_Eq(v.objKeys[i], key) {
|
||||
return v.objValues[i];
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return Json_Null();
|
||||
}
|
||||
return Json_Null();
|
||||
}
|
||||
|
||||
func Json_ObjectHas(v: JsonValue, key: String) -> bool {
|
||||
if v.tag != JsonTagObject { return false; }
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if String_Eq(v.objKeys[i], key) {
|
||||
return true;
|
||||
func Json_ObjectHas(v: JsonValue, key: String) -> bool {
|
||||
if v.tag != JsonTagObject { return false; }
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if String_Eq(v.objKeys[i], key) {
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Json_ObjectSet(self: *JsonValue, key: String, val: JsonValue) {
|
||||
if self.tag != JsonTagObject { return; }
|
||||
var i: uint = 0;
|
||||
while i < self.objLen {
|
||||
if String_Eq(self.objKeys[i], key) {
|
||||
self.objValues[i] = val;
|
||||
return;
|
||||
func Json_ObjectSet(self: *JsonValue, key: String, val: JsonValue) {
|
||||
if self.tag != JsonTagObject { return; }
|
||||
var i: uint = 0;
|
||||
while i < self.objLen {
|
||||
if String_Eq(self.objKeys[i], key) {
|
||||
self.objValues[i] = val;
|
||||
return;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if self.objLen >= self.objCap {
|
||||
let objNewCap: uint = self.objCap;
|
||||
if objNewCap == 0 {
|
||||
self.objCap = 4;
|
||||
self.objKeys = Alloc(4 * sizeof(String)) as *String;
|
||||
self.objValues = Alloc(4 * sizeof(JsonValue)) as *JsonValue;
|
||||
} else {
|
||||
let doubleCap: uint = objNewCap * 2;
|
||||
self.objCap = doubleCap;
|
||||
self.objKeys = Realloc(self.objKeys as *void, doubleCap * sizeof(String)) as *String;
|
||||
self.objValues = Realloc(self.objValues as *void, doubleCap * sizeof(JsonValue)) as *JsonValue;
|
||||
if self.objLen >= self.objCap {
|
||||
let objNewCap: uint = self.objCap;
|
||||
if objNewCap == 0 {
|
||||
self.objCap = 4;
|
||||
self.objKeys = Alloc(4 * sizeof(String)) as *String;
|
||||
self.objValues = Alloc(4 * sizeof(JsonValue)) as *JsonValue;
|
||||
} else {
|
||||
let doubleCap: uint = objNewCap * 2;
|
||||
self.objCap = doubleCap;
|
||||
self.objKeys = Realloc(self.objKeys as *void, doubleCap * sizeof(String)) as *String;
|
||||
self.objValues = Realloc(self.objValues as *void, doubleCap * sizeof(JsonValue)) as *JsonValue;
|
||||
}
|
||||
}
|
||||
self.objKeys[self.objLen] = key;
|
||||
self.objValues[self.objLen] = val;
|
||||
self.objLen = self.objLen + 1;
|
||||
}
|
||||
self.objKeys[self.objLen] = key;
|
||||
self.objValues[self.objLen] = val;
|
||||
self.objLen = self.objLen + 1;
|
||||
}
|
||||
|
||||
/* === Accessors === */
|
||||
func Json_IsNull(v: JsonValue) -> bool {
|
||||
return v.tag == JsonTagNull;
|
||||
}
|
||||
|
||||
func Json_AsBool(v: JsonValue) -> bool {
|
||||
if v.tag == JsonTagBool { return v.boolVal; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Json_AsNumber(v: JsonValue) -> float64 {
|
||||
if v.tag == JsonTagNumber { return v.numVal; }
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
func Json_AsString(v: JsonValue) -> String {
|
||||
if v.tag == JsonTagString { return v.strVal; }
|
||||
return "";
|
||||
}
|
||||
|
||||
/* === Parser === */
|
||||
struct JsonParser {
|
||||
src: String,
|
||||
pos: uint,
|
||||
len: uint,
|
||||
error: String
|
||||
}
|
||||
|
||||
func JsonParser_Peek(p: *JsonParser) -> int {
|
||||
if p.pos >= p.len { return 0; }
|
||||
return p.src[p.pos] as int;
|
||||
}
|
||||
|
||||
func JsonParser_Advance(p: *JsonParser) {
|
||||
if p.pos < p.len {
|
||||
p.pos = p.pos + 1;
|
||||
/* === Accessors === */
|
||||
func Json_IsNull(v: JsonValue) -> bool {
|
||||
return v.tag == JsonTagNull;
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_SkipWhitespace(p: *JsonParser) {
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 32 || c == 9 || c == 10 || c == 13 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
func Json_AsBool(v: JsonValue) -> bool {
|
||||
if v.tag == JsonTagBool { return v.boolVal; }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_Match(p: *JsonParser, expected: String) -> bool {
|
||||
let elen: uint = String_Len(expected);
|
||||
if p.pos + elen > p.len { return false; }
|
||||
var i: uint = 0;
|
||||
while i < elen {
|
||||
if p.src[p.pos + i] != expected[i] {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
func Json_AsNumber(v: JsonValue) -> float64 {
|
||||
if v.tag == JsonTagNumber { return v.numVal; }
|
||||
return 0.0;
|
||||
}
|
||||
p.pos = p.pos + elen;
|
||||
return true;
|
||||
}
|
||||
|
||||
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue;
|
||||
|
||||
func JsonParser_ParseString(p: *JsonParser) -> String {
|
||||
if JsonParser_Peek(p) != 34 {
|
||||
p.error = "Expected string";
|
||||
func Json_AsString(v: JsonValue) -> String {
|
||||
if v.tag == JsonTagString { return v.strVal; }
|
||||
return "";
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 0 || c == 34 {
|
||||
break;
|
||||
}
|
||||
if c == 92 {
|
||||
JsonParser_Advance(p);
|
||||
let esc: int = JsonParser_Peek(p);
|
||||
if esc == 0 {
|
||||
p.error = "Unterminated string escape";
|
||||
StringBuilder_Free(&sb);
|
||||
return "";
|
||||
}
|
||||
if esc == 110 { StringBuilder_AppendChar(&sb, 10 as char8); } // \n
|
||||
else if esc == 116 { StringBuilder_AppendChar(&sb, 9 as char8); } // \t
|
||||
else if esc == 114 { StringBuilder_AppendChar(&sb, 13 as char8); } // \r
|
||||
else if esc == 98 { StringBuilder_AppendChar(&sb, 8 as char8); } // \b
|
||||
else if esc == 102 { StringBuilder_AppendChar(&sb, 12 as char8); } // \f
|
||||
else if esc == 34 { StringBuilder_AppendChar(&sb, 34 as char8); } // \"
|
||||
else if esc == 92 { StringBuilder_AppendChar(&sb, 92 as char8); } // \\
|
||||
else {
|
||||
// Unknown escape — keep literal
|
||||
StringBuilder_AppendChar(&sb, 92 as char8);
|
||||
StringBuilder_AppendChar(&sb, esc as char8);
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
StringBuilder_AppendChar(&sb, c as char8);
|
||||
JsonParser_Advance(p);
|
||||
|
||||
/* === Parser === */
|
||||
struct JsonParser {
|
||||
src: String,
|
||||
pos: uint,
|
||||
len: uint,
|
||||
error: String
|
||||
}
|
||||
|
||||
func JsonParser_Peek(p: *JsonParser) -> int {
|
||||
if p.pos >= p.len { return 0; }
|
||||
return p.src[p.pos] as int;
|
||||
}
|
||||
|
||||
func JsonParser_Advance(p: *JsonParser) {
|
||||
if p.pos < p.len {
|
||||
p.pos = p.pos + 1;
|
||||
}
|
||||
}
|
||||
if JsonParser_Peek(p) != 34 {
|
||||
p.error = "Unterminated string";
|
||||
|
||||
func JsonParser_SkipWhitespace(p: *JsonParser) {
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 32 || c == 9 || c == 10 || c == 13 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_Match(p: *JsonParser, expected: String) -> bool {
|
||||
let elen: uint = String_Len(expected);
|
||||
if p.pos + elen > p.len { return false; }
|
||||
var i: uint = 0;
|
||||
while i < elen {
|
||||
if p.src[p.pos + i] != expected[i] {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
p.pos = p.pos + elen;
|
||||
return true;
|
||||
}
|
||||
|
||||
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue;
|
||||
|
||||
func JsonParser_ParseString(p: *JsonParser) -> String {
|
||||
if JsonParser_Peek(p) != 34 {
|
||||
p.error = "Expected string";
|
||||
return "";
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 0 || c == 34 {
|
||||
break;
|
||||
}
|
||||
if c == 92 {
|
||||
JsonParser_Advance(p);
|
||||
let esc: int = JsonParser_Peek(p);
|
||||
if esc == 0 {
|
||||
p.error = "Unterminated string escape";
|
||||
StringBuilder_Free(&sb);
|
||||
return "";
|
||||
}
|
||||
if esc == 110 { StringBuilder_AppendChar(&sb, 10 as char8); } // \n
|
||||
else if esc == 116 { StringBuilder_AppendChar(&sb, 9 as char8); } // \t
|
||||
else if esc == 114 { StringBuilder_AppendChar(&sb, 13 as char8); } // \r
|
||||
else if esc == 98 { StringBuilder_AppendChar(&sb, 8 as char8); } // \b
|
||||
else if esc == 102 { StringBuilder_AppendChar(&sb, 12 as char8); } // \f
|
||||
else if esc == 34 { StringBuilder_AppendChar(&sb, 34 as char8); } // \"
|
||||
else if esc == 92 { StringBuilder_AppendChar(&sb, 92 as char8); } // \\
|
||||
else {
|
||||
// Unknown escape — keep literal
|
||||
StringBuilder_AppendChar(&sb, 92 as char8);
|
||||
StringBuilder_AppendChar(&sb, esc as char8);
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
StringBuilder_AppendChar(&sb, c as char8);
|
||||
JsonParser_Advance(p);
|
||||
}
|
||||
}
|
||||
if JsonParser_Peek(p) != 34 {
|
||||
p.error = "Unterminated string";
|
||||
StringBuilder_Free(&sb);
|
||||
return "";
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return "";
|
||||
return result;
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
||||
let start: uint = p.pos;
|
||||
let c0: int = JsonParser_Peek(p);
|
||||
if c0 == 45 {
|
||||
JsonParser_Advance(p);
|
||||
}
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c >= 48 && c <= 57 {
|
||||
func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
||||
let start: uint = p.pos;
|
||||
let c0: int = JsonParser_Peek(p);
|
||||
if c0 == 45 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if JsonParser_Peek(p) == 46 {
|
||||
JsonParser_Advance(p);
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c >= 48 && c <= 57 {
|
||||
@@ -300,193 +290,203 @@ func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if JsonParser_Peek(p) == 46 {
|
||||
JsonParser_Advance(p);
|
||||
while true {
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c >= 48 && c <= 57 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let numStr: String = String_Slice(p.src, start, p.pos - start);
|
||||
let n: float64 = String_ToFloat(numStr);
|
||||
return Json_Number(n);
|
||||
}
|
||||
let numStr: String = String_Slice(p.src, start, p.pos - start);
|
||||
let n: float64 = String_ToFloat(numStr);
|
||||
return Json_Number(n);
|
||||
}
|
||||
|
||||
func JsonParser_ParseArray(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_Advance(p);
|
||||
var arr: JsonValue = Json_Array();
|
||||
JsonParser_SkipWhitespace(p);
|
||||
if JsonParser_Peek(p) == 93 {
|
||||
func JsonParser_ParseArray(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_Advance(p);
|
||||
return arr;
|
||||
}
|
||||
while true {
|
||||
var arr: JsonValue = Json_Array();
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let val: JsonValue = JsonParser_ParseValue(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
Json_ArrayPush(&arr, val);
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 93 {
|
||||
if JsonParser_Peek(p) == 93 {
|
||||
JsonParser_Advance(p);
|
||||
return arr;
|
||||
}
|
||||
if c == 44 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
p.error = "Expected ',' or ']' in array";
|
||||
return Json_Null();
|
||||
while true {
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let val: JsonValue = JsonParser_ParseValue(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
Json_ArrayPush(&arr, val);
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 93 {
|
||||
JsonParser_Advance(p);
|
||||
return arr;
|
||||
}
|
||||
if c == 44 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
p.error = "Expected ',' or ']' in array";
|
||||
return Json_Null();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_ParseObject(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_Advance(p);
|
||||
var obj: JsonValue = Json_Object();
|
||||
JsonParser_SkipWhitespace(p);
|
||||
if JsonParser_Peek(p) == 125 {
|
||||
func JsonParser_ParseObject(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_Advance(p);
|
||||
return obj;
|
||||
}
|
||||
while true {
|
||||
var obj: JsonValue = Json_Object();
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let key: String = JsonParser_ParseString(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
JsonParser_SkipWhitespace(p);
|
||||
if JsonParser_Peek(p) != 58 {
|
||||
p.error = "Expected ':' after object key";
|
||||
return Json_Null();
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let val: JsonValue = JsonParser_ParseValue(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
Json_ObjectSet(&obj, key, val);
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 125 {
|
||||
if JsonParser_Peek(p) == 125 {
|
||||
JsonParser_Advance(p);
|
||||
return obj;
|
||||
}
|
||||
if c == 44 {
|
||||
while true {
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let key: String = JsonParser_ParseString(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
JsonParser_SkipWhitespace(p);
|
||||
if JsonParser_Peek(p) != 58 {
|
||||
p.error = "Expected ':' after object key";
|
||||
return Json_Null();
|
||||
}
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
p.error = "Expected ',' or '}' in object";
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let val: JsonValue = JsonParser_ParseValue(p);
|
||||
if p.error != "" { return Json_Null(); }
|
||||
Json_ObjectSet(&obj, key, val);
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 125 {
|
||||
JsonParser_Advance(p);
|
||||
return obj;
|
||||
}
|
||||
if c == 44 {
|
||||
JsonParser_Advance(p);
|
||||
} else {
|
||||
p.error = "Expected ',' or '}' in object";
|
||||
return Json_Null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 0 {
|
||||
p.error = "Unexpected end of input";
|
||||
return Json_Null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue {
|
||||
JsonParser_SkipWhitespace(p);
|
||||
let c: int = JsonParser_Peek(p);
|
||||
if c == 0 {
|
||||
p.error = "Unexpected end of input";
|
||||
return Json_Null();
|
||||
}
|
||||
if c == 34 {
|
||||
return Json_String(JsonParser_ParseString(p));
|
||||
}
|
||||
if c == 123 {
|
||||
return JsonParser_ParseObject(p);
|
||||
}
|
||||
if c == 91 {
|
||||
return JsonParser_ParseArray(p);
|
||||
}
|
||||
if c == 116 {
|
||||
if JsonParser_Match(p, "true") {
|
||||
return Json_Bool(true);
|
||||
if c == 34 {
|
||||
return Json_String(JsonParser_ParseString(p));
|
||||
}
|
||||
p.error = "Expected 'true'";
|
||||
return Json_Null();
|
||||
}
|
||||
if c == 102 {
|
||||
if JsonParser_Match(p, "false") {
|
||||
return Json_Bool(false);
|
||||
if c == 123 {
|
||||
return JsonParser_ParseObject(p);
|
||||
}
|
||||
p.error = "Expected 'false'";
|
||||
return Json_Null();
|
||||
}
|
||||
if c == 110 {
|
||||
if JsonParser_Match(p, "null") {
|
||||
if c == 91 {
|
||||
return JsonParser_ParseArray(p);
|
||||
}
|
||||
if c == 116 {
|
||||
if JsonParser_Match(p, "true") {
|
||||
return Json_Bool(true);
|
||||
}
|
||||
p.error = "Expected 'true'";
|
||||
return Json_Null();
|
||||
}
|
||||
p.error = "Expected 'null'";
|
||||
if c == 102 {
|
||||
if JsonParser_Match(p, "false") {
|
||||
return Json_Bool(false);
|
||||
}
|
||||
p.error = "Expected 'false'";
|
||||
return Json_Null();
|
||||
}
|
||||
if c == 110 {
|
||||
if JsonParser_Match(p, "null") {
|
||||
return Json_Null();
|
||||
}
|
||||
p.error = "Expected 'null'";
|
||||
return Json_Null();
|
||||
}
|
||||
if (c >= 48 && c <= 57) || c == 45 {
|
||||
return JsonParser_ParseNumber(p);
|
||||
}
|
||||
p.error = "Unexpected character";
|
||||
return Json_Null();
|
||||
}
|
||||
if (c >= 48 && c <= 57) || c == 45 {
|
||||
return JsonParser_ParseNumber(p);
|
||||
}
|
||||
p.error = "Unexpected character";
|
||||
return Json_Null();
|
||||
}
|
||||
|
||||
/* === Public parser === */
|
||||
func Json_Parse(s: String) -> JsonValue {
|
||||
var p: JsonParser = JsonParser { src: s, pos: 0, len: String_Len(s), error: "" };
|
||||
let result: JsonValue = JsonParser_ParseValue(&p);
|
||||
JsonParser_SkipWhitespace(&p);
|
||||
if p.error == "" && p.pos != p.len {
|
||||
p.error = "Trailing data after JSON value";
|
||||
return Json_Null();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* === Serializer === */
|
||||
func Json_StringifyImpl(sb: *StringBuilder, v: JsonValue) {
|
||||
if v.tag == JsonTagNull {
|
||||
StringBuilder_Append(sb, "null");
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagBool {
|
||||
if v.boolVal {
|
||||
StringBuilder_Append(sb, "true");
|
||||
} else {
|
||||
StringBuilder_Append(sb, "false");
|
||||
/* === Public parser === */
|
||||
func Json_Parse(s: String) -> JsonValue {
|
||||
var p: JsonParser = JsonParser { src: s, pos: 0, len: String_Len(s), error: "" };
|
||||
let result: JsonValue = JsonParser_ParseValue(&p);
|
||||
JsonParser_SkipWhitespace(&p);
|
||||
if p.error == "" && p.pos != p.len {
|
||||
p.error = "Trailing data after JSON value";
|
||||
return Json_Null();
|
||||
}
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
if v.tag == JsonTagNumber {
|
||||
StringBuilder_AppendFloat(sb, v.numVal);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagString {
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_Append(sb, v.strVal);
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagArray {
|
||||
StringBuilder_AppendChar(sb, 91 as char8);
|
||||
var i: uint = 0;
|
||||
while i < v.arrLen {
|
||||
if i > 0 {
|
||||
StringBuilder_AppendChar(sb, 44 as char8);
|
||||
|
||||
/* === Serializer === */
|
||||
func Json_StringifyImpl(sb: *StringBuilder, v: JsonValue) {
|
||||
if v.tag == JsonTagNull {
|
||||
StringBuilder_Append(sb, "null");
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagBool {
|
||||
if v.boolVal {
|
||||
StringBuilder_Append(sb, "true");
|
||||
} else {
|
||||
StringBuilder_Append(sb, "false");
|
||||
}
|
||||
Json_StringifyImpl(sb, v.arrData[i]);
|
||||
i = i + 1;
|
||||
return;
|
||||
}
|
||||
StringBuilder_AppendChar(sb, 93 as char8);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagObject {
|
||||
StringBuilder_AppendChar(sb, 123 as char8);
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if i > 0 {
|
||||
StringBuilder_AppendChar(sb, 44 as char8);
|
||||
if v.tag == JsonTagNumber {
|
||||
StringBuilder_AppendFloat(sb, v.numVal);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagString {
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_Append(sb, v.strVal);
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagArray {
|
||||
StringBuilder_AppendChar(sb, 91 as char8);
|
||||
var i: uint = 0;
|
||||
while i < v.arrLen {
|
||||
if i > 0 {
|
||||
StringBuilder_AppendChar(sb, 44 as char8);
|
||||
}
|
||||
Json_StringifyImpl(sb, v.arrData[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_Append(sb, v.objKeys[i]);
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_AppendChar(sb, 58 as char8);
|
||||
Json_StringifyImpl(sb, v.objValues[i]);
|
||||
i = i + 1;
|
||||
StringBuilder_AppendChar(sb, 93 as char8);
|
||||
return;
|
||||
}
|
||||
if v.tag == JsonTagObject {
|
||||
StringBuilder_AppendChar(sb, 123 as char8);
|
||||
var i: uint = 0;
|
||||
while i < v.objLen {
|
||||
if i > 0 {
|
||||
StringBuilder_AppendChar(sb, 44 as char8);
|
||||
}
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_Append(sb, v.objKeys[i]);
|
||||
StringBuilder_AppendChar(sb, 34 as char8);
|
||||
StringBuilder_AppendChar(sb, 58 as char8);
|
||||
Json_StringifyImpl(sb, v.objValues[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
StringBuilder_AppendChar(sb, 125 as char8);
|
||||
return;
|
||||
}
|
||||
StringBuilder_AppendChar(sb, 125 as char8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
func Json_Stringify(v: JsonValue) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
Json_StringifyImpl(&sb, v);
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
func Json_Stringify(v: JsonValue) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
Json_StringifyImpl(&sb, v);
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+211
-203
@@ -1,242 +1,250 @@
|
||||
module Std::Map {
|
||||
|
||||
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
|
||||
extern func bux_hash_string(s: String) -> uint;
|
||||
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
|
||||
extern func bux_hash_string(s: String) -> uint;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Generic Map<K, V> — works with value-type keys (int, float, etc.)
|
||||
// For String keys, use StringMap below.
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// Generic Map<K, V> — works with value-type keys (int, float, etc.)
|
||||
// For String keys, use StringMap below.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct MapEntry<K, V> {
|
||||
key: K,
|
||||
value: V,
|
||||
occupied: bool,
|
||||
}
|
||||
|
||||
struct Map<K, V> {
|
||||
entries: *MapEntry<K, V>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func Map_New<K, V>(cap: uint) -> Map<K, V> {
|
||||
let total: uint = cap * sizeof(MapEntry<K, V>);
|
||||
let data: *MapEntry<K, V> = bux_alloc(total) as *MapEntry<K, V>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
struct MapEntry<K, V> {
|
||||
key: K,
|
||||
value: V,
|
||||
occupied: bool,
|
||||
}
|
||||
return Map<K, V> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
|
||||
func Map_Set<K, V>(m: *Map<K, V>, key: K, value: V) {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
m.entries[idx].value = value;
|
||||
return;
|
||||
struct Map<K, V> {
|
||||
entries: *MapEntry<K, V>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func Map_New<K, V>(cap: uint) -> Map<K, V> {
|
||||
let total: uint = cap * sizeof(MapEntry<K, V>);
|
||||
let data: *MapEntry<K, V> = bux_alloc(total) as *MapEntry<K, V>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
return Map<K, V> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
m.entries[idx].key = key;
|
||||
m.entries[idx].value = value;
|
||||
m.entries[idx].occupied = true;
|
||||
m.len = m.len + 1;
|
||||
}
|
||||
|
||||
func Map_Get<K, V>(m: *Map<K, V>, key: K) -> V {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
return m.entries[idx].value;
|
||||
func Map_Set<K, V>(m: *Map<K, V>, key: K, value: V) {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
m.entries[idx].value = value;
|
||||
return;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
m.entries[idx].key = key;
|
||||
m.entries[idx].value = value;
|
||||
m.entries[idx].occupied = true;
|
||||
m.len = m.len + 1;
|
||||
}
|
||||
// Return zero value for missing key
|
||||
var zero: V = 0 as V;
|
||||
return zero;
|
||||
}
|
||||
|
||||
func Map_Has<K, V>(m: *Map<K, V>, key: K) -> bool {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
return true;
|
||||
func Map_Get<K, V>(m: *Map<K, V>, key: K) -> V {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
return m.entries[idx].value;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
// Return zero value for missing key
|
||||
var zero: V = 0 as V;
|
||||
return zero;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Map_Len<K, V>(m: *Map<K, V>) -> uint {
|
||||
return m.len;
|
||||
}
|
||||
|
||||
func Map_IsEmpty<K, V>(m: *Map<K, V>) -> bool {
|
||||
return m.len == 0;
|
||||
}
|
||||
|
||||
/* Remove key if present. Rebuilds the table to keep open-addressing correct. */
|
||||
func Map_Remove<K, V>(m: *Map<K, V>, key: K) -> bool {
|
||||
if !Map_Has<K, V>(m, key) {
|
||||
func Map_Has<K, V>(m: *Map<K, V>, key: K) -> bool {
|
||||
var keyPtr: *K = &key;
|
||||
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if m.entries[idx].key == key {
|
||||
return true;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var fresh: Map<K, V> = Map_New<K, V>(m.cap);
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
if m.entries[i].occupied {
|
||||
if m.entries[i].key != key {
|
||||
Map_Set<K, V>(&fresh, m.entries[i].key, m.entries[i].value);
|
||||
|
||||
func Map_Len<K, V>(m: *Map<K, V>) -> uint {
|
||||
return m.len;
|
||||
}
|
||||
|
||||
func Map_IsEmpty<K, V>(m: *Map<K, V>) -> bool {
|
||||
return m.len == 0;
|
||||
}
|
||||
|
||||
/* Remove key if present. Rebuilds the table to keep open-addressing correct. */
|
||||
func Map_Remove<K, V>(m: *Map<K, V>, key: K) -> bool {
|
||||
if !Map_Has<K, V>(m, key) {
|
||||
return false;
|
||||
}
|
||||
var fresh: Map<K, V> = Map_New<K, V>(m.cap);
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
if m.entries[i].occupied {
|
||||
if m.entries[i].key != key {
|
||||
Map_Set<K, V>(&fresh, m.entries[i].key, m.entries[i].value);
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = fresh.entries;
|
||||
m.cap = fresh.cap;
|
||||
m.len = fresh.len;
|
||||
// Ownership transferred to `m` — clear `fresh` so auto-Drop does not free twice
|
||||
fresh.entries = null as *MapEntry<K, V>;
|
||||
fresh.cap = 0;
|
||||
fresh.len = 0;
|
||||
return true;
|
||||
}
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = fresh.entries;
|
||||
m.cap = fresh.cap;
|
||||
m.len = fresh.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
func Map_Clear<K, V>(m: *Map<K, V>) {
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
m.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
m.len = 0;
|
||||
}
|
||||
|
||||
func Map_Free<K, V>(m: *Map<K, V>) {
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = null as *MapEntry<K, V>;
|
||||
m.cap = 0;
|
||||
m.len = 0;
|
||||
}
|
||||
|
||||
func Map_Drop<K, V>(m: *Map<K, V>) {
|
||||
Map_Free<K, V>(m);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// StringMap<V> — specialized Map for String keys, using strcmp
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct StringMapEntry<V> {
|
||||
key: String,
|
||||
value: V,
|
||||
occupied: bool,
|
||||
}
|
||||
|
||||
struct StringMap<V> {
|
||||
entries: *StringMapEntry<V>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func StringMap_New<V>(cap: uint) -> StringMap<V> {
|
||||
let total: uint = cap * sizeof(StringMapEntry<V>);
|
||||
let data: *StringMapEntry<V> = bux_alloc(total) as *StringMapEntry<V>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
return StringMap<V> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
|
||||
func StringMap_Set<V>(m: *StringMap<V>, key: String, value: V) {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
m.entries[idx].value = value;
|
||||
return;
|
||||
func Map_Clear<K, V>(m: *Map<K, V>) {
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
m.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
m.len = 0;
|
||||
}
|
||||
m.entries[idx].key = key;
|
||||
m.entries[idx].value = value;
|
||||
m.entries[idx].occupied = true;
|
||||
m.len = m.len + 1;
|
||||
}
|
||||
|
||||
func StringMap_Get<V>(m: *StringMap<V>, key: String) -> V {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
return m.entries[idx].value;
|
||||
func Map_Free<K, V>(m: *Map<K, V>) {
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = null as *MapEntry<K, V>;
|
||||
m.cap = 0;
|
||||
m.len = 0;
|
||||
}
|
||||
|
||||
func Map_Drop<K, V>(m: *Map<K, V>) {
|
||||
Map_Free<K, V>(m);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// StringMap<V> — specialized Map for String keys, using strcmp
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct StringMapEntry<V> {
|
||||
key: String,
|
||||
value: V,
|
||||
occupied: bool,
|
||||
}
|
||||
|
||||
struct StringMap<V> {
|
||||
entries: *StringMapEntry<V>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func StringMap_New<V>(cap: uint) -> StringMap<V> {
|
||||
let total: uint = cap * sizeof(StringMapEntry<V>);
|
||||
let data: *StringMapEntry<V> = bux_alloc(total) as *StringMapEntry<V>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
return StringMap<V> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
var zero: V = 0 as V;
|
||||
return zero;
|
||||
}
|
||||
|
||||
func StringMap_Has<V>(m: *StringMap<V>, key: String) -> bool {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
return true;
|
||||
func StringMap_Set<V>(m: *StringMap<V>, key: String, value: V) {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
m.entries[idx].value = value;
|
||||
return;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
m.entries[idx].key = key;
|
||||
m.entries[idx].value = value;
|
||||
m.entries[idx].occupied = true;
|
||||
m.len = m.len + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func StringMap_Len<V>(m: *StringMap<V>) -> uint {
|
||||
return m.len;
|
||||
}
|
||||
func StringMap_Get<V>(m: *StringMap<V>, key: String) -> V {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
return m.entries[idx].value;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
var zero: V = 0 as V;
|
||||
return zero;
|
||||
}
|
||||
|
||||
func StringMap_IsEmpty<V>(m: *StringMap<V>) -> bool {
|
||||
return m.len == 0;
|
||||
}
|
||||
|
||||
func StringMap_Remove<V>(m: *StringMap<V>, key: String) -> bool {
|
||||
if !StringMap_Has<V>(m, key) {
|
||||
func StringMap_Has<V>(m: *StringMap<V>, key: String) -> bool {
|
||||
let hash: uint = bux_hash_string(key);
|
||||
var idx: uint = hash % m.cap;
|
||||
while m.entries[idx].occupied {
|
||||
if String_Eq(m.entries[idx].key, key) {
|
||||
return true;
|
||||
}
|
||||
idx = (idx + 1) % m.cap;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var fresh: StringMap<V> = StringMap_New<V>(m.cap);
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
if m.entries[i].occupied {
|
||||
if !String_Eq(m.entries[i].key, key) {
|
||||
StringMap_Set<V>(&fresh, m.entries[i].key, m.entries[i].value);
|
||||
}
|
||||
|
||||
func StringMap_Len<V>(m: *StringMap<V>) -> uint {
|
||||
return m.len;
|
||||
}
|
||||
|
||||
func StringMap_IsEmpty<V>(m: *StringMap<V>) -> bool {
|
||||
return m.len == 0;
|
||||
}
|
||||
|
||||
func StringMap_Remove<V>(m: *StringMap<V>, key: String) -> bool {
|
||||
if !StringMap_Has<V>(m, key) {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
var fresh: StringMap<V> = StringMap_New<V>(m.cap);
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
if m.entries[i].occupied {
|
||||
if !String_Eq(m.entries[i].key, key) {
|
||||
StringMap_Set<V>(&fresh, m.entries[i].key, m.entries[i].value);
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = fresh.entries;
|
||||
m.cap = fresh.cap;
|
||||
m.len = fresh.len;
|
||||
// Ownership transferred to `m` — clear `fresh` so auto-Drop does not free twice
|
||||
fresh.entries = null as *StringMapEntry<V>;
|
||||
fresh.cap = 0;
|
||||
fresh.len = 0;
|
||||
return true;
|
||||
}
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = fresh.entries;
|
||||
m.cap = fresh.cap;
|
||||
m.len = fresh.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
func StringMap_Clear<V>(m: *StringMap<V>) {
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
m.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
func StringMap_Clear<V>(m: *StringMap<V>) {
|
||||
var i: uint = 0;
|
||||
while i < m.cap {
|
||||
m.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
m.len = 0;
|
||||
}
|
||||
m.len = 0;
|
||||
}
|
||||
|
||||
func StringMap_Free<V>(m: *StringMap<V>) {
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = null as *StringMapEntry<V>;
|
||||
m.cap = 0;
|
||||
m.len = 0;
|
||||
}
|
||||
func StringMap_Free<V>(m: *StringMap<V>) {
|
||||
bux_free(m.entries as *void);
|
||||
m.entries = null as *StringMapEntry<V>;
|
||||
m.cap = 0;
|
||||
m.len = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+40
-40
@@ -1,44 +1,44 @@
|
||||
module Std::Math {
|
||||
|
||||
extern func bux_sqrt(x: float64) -> float64;
|
||||
extern func bux_pow(x: float64, y: float64) -> float64;
|
||||
extern func bux_abs_i64(x: int64) -> int64;
|
||||
extern func bux_abs_f64(x: float64) -> float64;
|
||||
extern func bux_min_i64(a: int64, b: int64) -> int64;
|
||||
extern func bux_max_i64(a: int64, b: int64) -> int64;
|
||||
extern func bux_min_f64(a: float64, b: float64) -> float64;
|
||||
extern func bux_max_f64(a: float64, b: float64) -> float64;
|
||||
extern func bux_sqrt(x: float64) -> float64;
|
||||
extern func bux_pow(x: float64, y: float64) -> float64;
|
||||
extern func bux_abs_i64(x: int64) -> int64;
|
||||
extern func bux_abs_f64(x: float64) -> float64;
|
||||
extern func bux_min_i64(a: int64, b: int64) -> int64;
|
||||
extern func bux_max_i64(a: int64, b: int64) -> int64;
|
||||
extern func bux_min_f64(a: float64, b: float64) -> float64;
|
||||
extern func bux_max_f64(a: float64, b: float64) -> float64;
|
||||
|
||||
func Sqrt(x: float64) -> float64 {
|
||||
return bux_sqrt(x);
|
||||
}
|
||||
|
||||
func Pow(x: float64, y: float64) -> float64 {
|
||||
return bux_pow(x, y);
|
||||
}
|
||||
|
||||
func Abs(n: int64) -> int64 {
|
||||
return bux_abs_i64(n);
|
||||
}
|
||||
|
||||
func AbsF(f: float64) -> float64 {
|
||||
return bux_abs_f64(f);
|
||||
}
|
||||
|
||||
func Min(a: int64, b: int64) -> int64 {
|
||||
return bux_min_i64(a, b);
|
||||
}
|
||||
|
||||
func Max(a: int64, b: int64) -> int64 {
|
||||
return bux_max_i64(a, b);
|
||||
}
|
||||
|
||||
func MinF(a: float64, b: float64) -> float64 {
|
||||
return bux_min_f64(a, b);
|
||||
}
|
||||
|
||||
func MaxF(a: float64, b: float64) -> float64 {
|
||||
return bux_max_f64(a, b);
|
||||
}
|
||||
|
||||
func Sqrt(x: float64) -> float64 {
|
||||
return bux_sqrt(x);
|
||||
}
|
||||
|
||||
func Pow(x: float64, y: float64) -> float64 {
|
||||
return bux_pow(x, y);
|
||||
}
|
||||
|
||||
func Abs(n: int64) -> int64 {
|
||||
return bux_abs_i64(n);
|
||||
}
|
||||
|
||||
func AbsF(f: float64) -> float64 {
|
||||
return bux_abs_f64(f);
|
||||
}
|
||||
|
||||
func Min(a: int64, b: int64) -> int64 {
|
||||
return bux_min_i64(a, b);
|
||||
}
|
||||
|
||||
func Max(a: int64, b: int64) -> int64 {
|
||||
return bux_max_i64(a, b);
|
||||
}
|
||||
|
||||
func MinF(a: float64, b: float64) -> float64 {
|
||||
return bux_min_f64(a, b);
|
||||
}
|
||||
|
||||
func MaxF(a: float64, b: float64) -> float64 {
|
||||
return bux_max_f64(a, b);
|
||||
}
|
||||
|
||||
}
|
||||
+20
-20
@@ -1,29 +1,29 @@
|
||||
module Std::Mem {
|
||||
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_realloc(ptr: *void, size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_realloc(ptr: *void, size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
|
||||
|
||||
func Alloc(size: uint) -> *void {
|
||||
return bux_alloc(size);
|
||||
}
|
||||
func Alloc(size: uint) -> *void {
|
||||
return bux_alloc(size);
|
||||
}
|
||||
|
||||
func Realloc(ptr: *void, size: uint) -> *void {
|
||||
return bux_realloc(ptr, size);
|
||||
}
|
||||
func Realloc(ptr: *void, size: uint) -> *void {
|
||||
return bux_realloc(ptr, size);
|
||||
}
|
||||
|
||||
func Free(ptr: *void) {
|
||||
bux_free(ptr);
|
||||
}
|
||||
func Free(ptr: *void) {
|
||||
bux_free(ptr);
|
||||
}
|
||||
|
||||
func MemEq(a: *void, b: *void, size: uint) -> bool {
|
||||
return bux_mem_eq(a, b, size) != 0;
|
||||
}
|
||||
func MemEq(a: *void, b: *void, size: uint) -> bool {
|
||||
return bux_mem_eq(a, b, size) != 0;
|
||||
}
|
||||
|
||||
func New<T>() -> *T {
|
||||
let sz: uint = sizeof(T);
|
||||
return bux_alloc(sz) as *T;
|
||||
}
|
||||
func New<T>() -> *T {
|
||||
let sz: uint = sizeof(T);
|
||||
return bux_alloc(sz) as *T;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-50
@@ -1,62 +1,62 @@
|
||||
module Std::Net {
|
||||
extern func bux_socket_create() -> int;
|
||||
extern func bux_socket_reuse(fd: int) -> int;
|
||||
extern func bux_socket_bind(fd: int, addr: String, port: int) -> int;
|
||||
extern func bux_socket_listen(fd: int, backlog: int) -> int;
|
||||
extern func bux_socket_accept(fd: int) -> int;
|
||||
extern func bux_socket_connect(fd: int, addr: String, port: int) -> int;
|
||||
extern func bux_socket_send(fd: int, data: String, len: int) -> int;
|
||||
extern func bux_socket_recv(fd: int, maxLen: int) -> String;
|
||||
extern func bux_socket_close(fd: int) -> int;
|
||||
extern func bux_socket_error() -> String;
|
||||
extern func bux_socket_create() -> int;
|
||||
extern func bux_socket_reuse(fd: int) -> int;
|
||||
extern func bux_socket_bind(fd: int, addr: String, port: int) -> int;
|
||||
extern func bux_socket_listen(fd: int, backlog: int) -> int;
|
||||
extern func bux_socket_accept(fd: int) -> int;
|
||||
extern func bux_socket_connect(fd: int, addr: String, port: int) -> int;
|
||||
extern func bux_socket_send(fd: int, data: String, len: int) -> int;
|
||||
extern func bux_socket_recv(fd: int, maxLen: int) -> String;
|
||||
extern func bux_socket_close(fd: int) -> int;
|
||||
extern func bux_socket_error() -> String;
|
||||
|
||||
/* Create a TCP socket. Returns -1 on error. */
|
||||
func Net_Create() -> int {
|
||||
return bux_socket_create();
|
||||
}
|
||||
/* Create a TCP socket. Returns -1 on error. */
|
||||
func Net_Create() -> int {
|
||||
return bux_socket_create();
|
||||
}
|
||||
|
||||
/* Enable SO_REUSEADDR on a socket. */
|
||||
func Net_SetReuse(fd: int) -> bool {
|
||||
return bux_socket_reuse(fd) == 0;
|
||||
}
|
||||
/* Enable SO_REUSEADDR on a socket. */
|
||||
func Net_SetReuse(fd: int) -> bool {
|
||||
return bux_socket_reuse(fd) == 0;
|
||||
}
|
||||
|
||||
/* Bind a socket to an address and port. */
|
||||
func Net_Bind(fd: int, addr: String, port: int) -> bool {
|
||||
return bux_socket_bind(fd, addr, port) == 0;
|
||||
}
|
||||
/* Bind a socket to an address and port. */
|
||||
func Net_Bind(fd: int, addr: String, port: int) -> bool {
|
||||
return bux_socket_bind(fd, addr, port) == 0;
|
||||
}
|
||||
|
||||
/* Start listening for connections. */
|
||||
func Net_Listen(fd: int, backlog: int) -> bool {
|
||||
return bux_socket_listen(fd, backlog) == 0;
|
||||
}
|
||||
/* Start listening for connections. */
|
||||
func Net_Listen(fd: int, backlog: int) -> bool {
|
||||
return bux_socket_listen(fd, backlog) == 0;
|
||||
}
|
||||
|
||||
/* Accept a connection. Returns new fd or -1 on error. */
|
||||
func Net_Accept(fd: int) -> int {
|
||||
return bux_socket_accept(fd);
|
||||
}
|
||||
/* Accept a connection. Returns new fd or -1 on error. */
|
||||
func Net_Accept(fd: int) -> int {
|
||||
return bux_socket_accept(fd);
|
||||
}
|
||||
|
||||
/* Connect to a remote address and port. */
|
||||
func Net_Connect(fd: int, addr: String, port: int) -> bool {
|
||||
return bux_socket_connect(fd, addr, port) == 0;
|
||||
}
|
||||
/* Connect to a remote address and port. */
|
||||
func Net_Connect(fd: int, addr: String, port: int) -> bool {
|
||||
return bux_socket_connect(fd, addr, port) == 0;
|
||||
}
|
||||
|
||||
/* Send data. Returns bytes sent or -1 on error. */
|
||||
func Net_Send(fd: int, data: String) -> int {
|
||||
return bux_socket_send(fd, data, bux_strlen(data) as int);
|
||||
}
|
||||
/* Send data. Returns bytes sent or -1 on error. */
|
||||
func Net_Send(fd: int, data: String) -> int {
|
||||
return bux_socket_send(fd, data, bux_strlen(data) as int);
|
||||
}
|
||||
|
||||
/* Receive up to maxLen bytes. Returns empty string on error/EOF. */
|
||||
func Net_Recv(fd: int, maxLen: int) -> String {
|
||||
return bux_socket_recv(fd, maxLen);
|
||||
}
|
||||
/* Receive up to maxLen bytes. Returns empty string on error/EOF. */
|
||||
func Net_Recv(fd: int, maxLen: int) -> String {
|
||||
return bux_socket_recv(fd, maxLen);
|
||||
}
|
||||
|
||||
/* Close a socket. */
|
||||
func Net_Close(fd: int) -> bool {
|
||||
return bux_socket_close(fd) == 0;
|
||||
}
|
||||
/* Close a socket. */
|
||||
func Net_Close(fd: int) -> bool {
|
||||
return bux_socket_close(fd) == 0;
|
||||
}
|
||||
|
||||
/* Get last socket error as a string. */
|
||||
func Net_LastError() -> String {
|
||||
return bux_socket_error();
|
||||
}
|
||||
/* Get last socket error as a string. */
|
||||
func Net_LastError() -> String {
|
||||
return bux_socket_error();
|
||||
}
|
||||
}
|
||||
|
||||
+52
-52
@@ -1,61 +1,61 @@
|
||||
module Std::Option {
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Io::{PrintLine};
|
||||
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_exit(code: int);
|
||||
|
||||
enum Option {
|
||||
Some(int),
|
||||
None,
|
||||
}
|
||||
|
||||
func Option_NewSome(value: int) -> Option {
|
||||
let o: Option = Option { tag: Option_Some };
|
||||
o.data.Some_0 = value;
|
||||
return o;
|
||||
}
|
||||
|
||||
func Option_NewNone() -> Option {
|
||||
return Option { tag: Option_None };
|
||||
}
|
||||
|
||||
func Option_IsSome(o: Option) -> bool {
|
||||
return o.tag == Option_Some;
|
||||
}
|
||||
|
||||
func Option_IsNone(o: Option) -> bool {
|
||||
return o.tag == Option_None;
|
||||
}
|
||||
|
||||
func Option_Unwrap(o: Option) -> int {
|
||||
if o.tag != Option_Some {
|
||||
PrintLine("panic: unwrap on None");
|
||||
return 0;
|
||||
enum Option {
|
||||
Some(int),
|
||||
None,
|
||||
}
|
||||
return o.data.Some_0;
|
||||
}
|
||||
|
||||
func Option_UnwrapOr(o: Option, fallback: int) -> int {
|
||||
if o.tag == Option_Some {
|
||||
return o.data.Some_0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* Unwrap Some or panic with a custom message */
|
||||
func Option_Expect(o: Option, msg: String) -> int {
|
||||
if o.tag != Option_Some {
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
return o.data.Some_0;
|
||||
}
|
||||
|
||||
/* If o is Some return it, otherwise return other */
|
||||
func Option_Or(o: Option, other: Option) -> Option {
|
||||
if o.tag == Option_Some {
|
||||
func Option_NewSome(value: int) -> Option {
|
||||
let o: Option = Option { tag: Option_Some };
|
||||
o.data.Some_0 = value;
|
||||
return o;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
func Option_NewNone() -> Option {
|
||||
return Option { tag: Option_None };
|
||||
}
|
||||
|
||||
func Option_IsSome(o: Option) -> bool {
|
||||
return o.tag == Option_Some;
|
||||
}
|
||||
|
||||
func Option_IsNone(o: Option) -> bool {
|
||||
return o.tag == Option_None;
|
||||
}
|
||||
|
||||
func Option_Unwrap(o: Option) -> int {
|
||||
if o.tag != Option_Some {
|
||||
PrintLine("panic: unwrap on None");
|
||||
return 0;
|
||||
}
|
||||
return o.data.Some_0;
|
||||
}
|
||||
|
||||
func Option_UnwrapOr(o: Option, fallback: int) -> int {
|
||||
if o.tag == Option_Some {
|
||||
return o.data.Some_0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* Unwrap Some or panic with a custom message */
|
||||
func Option_Expect(o: Option, msg: String) -> int {
|
||||
if o.tag != Option_Some {
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
return o.data.Some_0;
|
||||
}
|
||||
|
||||
/* If o is Some return it, otherwise return other */
|
||||
func Option_Or(o: Option, other: Option) -> Option {
|
||||
if o.tag == Option_Some {
|
||||
return o;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+29
-29
@@ -1,40 +1,40 @@
|
||||
module Std::Os {
|
||||
|
||||
extern func bux_argc() -> int;
|
||||
extern func bux_argv(index: int) -> String;
|
||||
extern func bux_getenv(name: String) -> String;
|
||||
extern func bux_setenv(name: String, value: String) -> int;
|
||||
extern func bux_getcwd() -> String;
|
||||
extern func bux_chdir(path: String) -> int;
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_argc() -> int;
|
||||
extern func bux_argv(index: int) -> String;
|
||||
extern func bux_getenv(name: String) -> String;
|
||||
extern func bux_setenv(name: String, value: String) -> int;
|
||||
extern func bux_getcwd() -> String;
|
||||
extern func bux_chdir(path: String) -> int;
|
||||
extern func bux_exit(code: int);
|
||||
|
||||
func Os_ArgsCount() -> int {
|
||||
return bux_argc();
|
||||
}
|
||||
func Os_ArgsCount() -> int {
|
||||
return bux_argc();
|
||||
}
|
||||
|
||||
func Os_Args(index: int) -> String {
|
||||
return bux_argv(index);
|
||||
}
|
||||
func Os_Args(index: int) -> String {
|
||||
return bux_argv(index);
|
||||
}
|
||||
|
||||
func Os_GetEnv(name: String) -> String {
|
||||
return bux_getenv(name);
|
||||
}
|
||||
func Os_GetEnv(name: String) -> String {
|
||||
return bux_getenv(name);
|
||||
}
|
||||
|
||||
func Os_SetEnv(name: String, value: String) -> bool {
|
||||
return bux_setenv(name, value) == 0;
|
||||
}
|
||||
func Os_SetEnv(name: String, value: String) -> bool {
|
||||
return bux_setenv(name, value) == 0;
|
||||
}
|
||||
|
||||
func Os_GetCwd() -> String {
|
||||
return bux_getcwd();
|
||||
}
|
||||
func Os_GetCwd() -> String {
|
||||
return bux_getcwd();
|
||||
}
|
||||
|
||||
func Os_Chdir(path: String) -> bool {
|
||||
return bux_chdir(path) == 0;
|
||||
}
|
||||
func Os_Chdir(path: String) -> bool {
|
||||
return bux_chdir(path) == 0;
|
||||
}
|
||||
|
||||
/* Terminate the process with the given exit code */
|
||||
func Os_Exit(code: int) {
|
||||
bux_exit(code);
|
||||
}
|
||||
/* Terminate the process with the given exit code */
|
||||
func Os_Exit(code: int) {
|
||||
bux_exit(code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,19 +1,19 @@
|
||||
module Std::Path {
|
||||
|
||||
extern func bux_path_join(a: String, b: String) -> String;
|
||||
extern func bux_path_parent(path: String) -> String;
|
||||
extern func bux_path_ext(path: String) -> String;
|
||||
extern func bux_path_join(a: String, b: String) -> String;
|
||||
extern func bux_path_parent(path: String) -> String;
|
||||
extern func bux_path_ext(path: String) -> String;
|
||||
|
||||
func Path_Join(a: String, b: String) -> String {
|
||||
return bux_path_join(a, b);
|
||||
}
|
||||
|
||||
func Path_Parent(path: String) -> String {
|
||||
return bux_path_parent(path);
|
||||
}
|
||||
|
||||
func Path_Ext(path: String) -> String {
|
||||
return bux_path_ext(path);
|
||||
}
|
||||
|
||||
func Path_Join(a: String, b: String) -> String {
|
||||
return bux_path_join(a, b);
|
||||
}
|
||||
|
||||
func Path_Parent(path: String) -> String {
|
||||
return bux_path_parent(path);
|
||||
}
|
||||
|
||||
func Path_Ext(path: String) -> String {
|
||||
return bux_path_ext(path);
|
||||
}
|
||||
|
||||
}
|
||||
+8
-8
@@ -1,14 +1,14 @@
|
||||
module Std::Process {
|
||||
|
||||
extern func bux_process_run(cmd: String) -> int;
|
||||
extern func bux_process_output(cmd: String) -> String;
|
||||
extern func bux_process_run(cmd: String) -> int;
|
||||
extern func bux_process_output(cmd: String) -> String;
|
||||
|
||||
func Process_Run(cmd: String) -> int {
|
||||
return bux_process_run(cmd);
|
||||
}
|
||||
func Process_Run(cmd: String) -> int {
|
||||
return bux_process_run(cmd);
|
||||
}
|
||||
|
||||
func Process_Output(cmd: String) -> String {
|
||||
return bux_process_output(cmd);
|
||||
}
|
||||
func Process_Output(cmd: String) -> String {
|
||||
return bux_process_output(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+63
-63
@@ -1,72 +1,72 @@
|
||||
module Std::Result {
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Io::{PrintLine};
|
||||
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_exit(code: int);
|
||||
|
||||
enum Result {
|
||||
Ok(int),
|
||||
Err(String),
|
||||
}
|
||||
|
||||
func Result_NewOk(value: int) -> Result {
|
||||
let r: Result = Result { tag: Result_Ok };
|
||||
r.data.Ok_0 = value;
|
||||
return r;
|
||||
}
|
||||
|
||||
func Result_NewErr(msg: String) -> Result {
|
||||
let r: Result = Result { tag: Result_Err };
|
||||
r.data.Err_0 = msg;
|
||||
return r;
|
||||
}
|
||||
|
||||
func Result_IsOk(r: Result) -> bool {
|
||||
return r.tag == Result_Ok;
|
||||
}
|
||||
|
||||
func Result_IsErr(r: Result) -> bool {
|
||||
return r.tag == Result_Err;
|
||||
}
|
||||
|
||||
func Result_Unwrap(r: Result) -> int {
|
||||
if r.tag != Result_Ok {
|
||||
PrintLine("panic: unwrap on Err");
|
||||
return 0;
|
||||
enum Result {
|
||||
Ok(int),
|
||||
Err(String),
|
||||
}
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
|
||||
func Result_UnwrapOr(r: Result, fallback: int) -> int {
|
||||
if r.tag == Result_Ok {
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* Unwrap Ok or panic with a custom message */
|
||||
func Result_Expect(r: Result, msg: String) -> int {
|
||||
if r.tag != Result_Ok {
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
|
||||
/* Extract Err payload (panics if Ok) */
|
||||
func Result_UnwrapErr(r: Result) -> String {
|
||||
if r.tag != Result_Err {
|
||||
PrintLine("panic: unwrap_err on Ok");
|
||||
return "";
|
||||
}
|
||||
return r.data.Err_0;
|
||||
}
|
||||
|
||||
/* If r is Ok return it, otherwise return other */
|
||||
func Result_Or(r: Result, other: Result) -> Result {
|
||||
if r.tag == Result_Ok {
|
||||
func Result_NewOk(value: int) -> Result {
|
||||
let r: Result = Result { tag: Result_Ok };
|
||||
r.data.Ok_0 = value;
|
||||
return r;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
func Result_NewErr(msg: String) -> Result {
|
||||
let r: Result = Result { tag: Result_Err };
|
||||
r.data.Err_0 = msg;
|
||||
return r;
|
||||
}
|
||||
|
||||
func Result_IsOk(r: Result) -> bool {
|
||||
return r.tag == Result_Ok;
|
||||
}
|
||||
|
||||
func Result_IsErr(r: Result) -> bool {
|
||||
return r.tag == Result_Err;
|
||||
}
|
||||
|
||||
func Result_Unwrap(r: Result) -> int {
|
||||
if r.tag != Result_Ok {
|
||||
PrintLine("panic: unwrap on Err");
|
||||
return 0;
|
||||
}
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
|
||||
func Result_UnwrapOr(r: Result, fallback: int) -> int {
|
||||
if r.tag == Result_Ok {
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* Unwrap Ok or panic with a custom message */
|
||||
func Result_Expect(r: Result, msg: String) -> int {
|
||||
if r.tag != Result_Ok {
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
return r.data.Ok_0;
|
||||
}
|
||||
|
||||
/* Extract Err payload (panics if Ok) */
|
||||
func Result_UnwrapErr(r: Result) -> String {
|
||||
if r.tag != Result_Err {
|
||||
PrintLine("panic: unwrap_err on Ok");
|
||||
return "";
|
||||
}
|
||||
return r.data.Err_0;
|
||||
}
|
||||
|
||||
/* If r is Ok return it, otherwise return other */
|
||||
func Result_Or(r: Result, other: Result) -> Result {
|
||||
if r.tag == Result_Ok {
|
||||
return r;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+95
-91
@@ -1,112 +1,116 @@
|
||||
module Std::Set {
|
||||
|
||||
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
|
||||
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
|
||||
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
extern func bux_free(ptr: *void);
|
||||
|
||||
struct SetEntry<T> {
|
||||
value: T,
|
||||
occupied: bool,
|
||||
}
|
||||
|
||||
struct Set<T> {
|
||||
entries: *SetEntry<T>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func Set_New<T>(cap: uint) -> Set<T> {
|
||||
let total: uint = cap * sizeof(SetEntry<T>);
|
||||
let data: *SetEntry<T> = bux_alloc(total) as *SetEntry<T>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
struct SetEntry<T> {
|
||||
value: T,
|
||||
occupied: bool,
|
||||
}
|
||||
return Set<T> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
|
||||
func Set_Add<T>(s: *Set<T>, value: T) {
|
||||
var valuePtr: *T = &value;
|
||||
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
|
||||
var idx: uint = hash % s.cap;
|
||||
while s.entries[idx].occupied {
|
||||
var entryPtr: *T = &s.entries[idx].value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
|
||||
return;
|
||||
struct Set<T> {
|
||||
entries: *SetEntry<T>,
|
||||
cap: uint,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func Set_New<T>(cap: uint) -> Set<T> {
|
||||
let total: uint = cap * sizeof(SetEntry<T>);
|
||||
let data: *SetEntry<T> = bux_alloc(total) as *SetEntry<T>;
|
||||
var i: uint = 0;
|
||||
while i < cap {
|
||||
data[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
idx = (idx + 1) % s.cap;
|
||||
return Set<T> { entries: data, cap: cap, len: 0 };
|
||||
}
|
||||
s.entries[idx].value = value;
|
||||
s.entries[idx].occupied = true;
|
||||
s.len = s.len + 1;
|
||||
}
|
||||
|
||||
func Set_Has<T>(s: *Set<T>, value: T) -> bool {
|
||||
var valuePtr: *T = &value;
|
||||
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
|
||||
var idx: uint = hash % s.cap;
|
||||
while s.entries[idx].occupied {
|
||||
var entryPtr: *T = &s.entries[idx].value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
|
||||
return true;
|
||||
func Set_Add<T>(s: *Set<T>, value: T) {
|
||||
var valuePtr: *T = &value;
|
||||
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
|
||||
var idx: uint = hash % s.cap;
|
||||
while s.entries[idx].occupied {
|
||||
var entryPtr: *T = &s.entries[idx].value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
|
||||
return;
|
||||
}
|
||||
idx = (idx + 1) % s.cap;
|
||||
}
|
||||
idx = (idx + 1) % s.cap;
|
||||
s.entries[idx].value = value;
|
||||
s.entries[idx].occupied = true;
|
||||
s.len = s.len + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Set_Len<T>(s: *Set<T>) -> uint {
|
||||
return s.len;
|
||||
}
|
||||
|
||||
func Set_IsEmpty<T>(s: *Set<T>) -> bool {
|
||||
return s.len == 0;
|
||||
}
|
||||
|
||||
/* Remove value if present. Rebuilds the table to keep open-addressing correct. */
|
||||
func Set_Remove<T>(s: *Set<T>, value: T) -> bool {
|
||||
if !Set_Has<T>(s, value) {
|
||||
func Set_Has<T>(s: *Set<T>, value: T) -> bool {
|
||||
var valuePtr: *T = &value;
|
||||
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
|
||||
var idx: uint = hash % s.cap;
|
||||
while s.entries[idx].occupied {
|
||||
var entryPtr: *T = &s.entries[idx].value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
|
||||
return true;
|
||||
}
|
||||
idx = (idx + 1) % s.cap;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var fresh: Set<T> = Set_New<T>(s.cap);
|
||||
var i: uint = 0;
|
||||
while i < s.cap {
|
||||
if s.entries[i].occupied {
|
||||
var entryPtr: *T = &s.entries[i].value;
|
||||
var valuePtr: *T = &value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) == 0 {
|
||||
Set_Add<T>(&fresh, s.entries[i].value);
|
||||
}
|
||||
|
||||
func Set_Len<T>(s: *Set<T>) -> uint {
|
||||
return s.len;
|
||||
}
|
||||
|
||||
func Set_IsEmpty<T>(s: *Set<T>) -> bool {
|
||||
return s.len == 0;
|
||||
}
|
||||
|
||||
/* Remove value if present. Rebuilds the table to keep open-addressing correct. */
|
||||
func Set_Remove<T>(s: *Set<T>, value: T) -> bool {
|
||||
if !Set_Has<T>(s, value) {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
var fresh: Set<T> = Set_New<T>(s.cap);
|
||||
var i: uint = 0;
|
||||
while i < s.cap {
|
||||
if s.entries[i].occupied {
|
||||
var entryPtr: *T = &s.entries[i].value;
|
||||
var valuePtr: *T = &value;
|
||||
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) == 0 {
|
||||
Set_Add<T>(&fresh, s.entries[i].value);
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
bux_free(s.entries as *void);
|
||||
s.entries = fresh.entries;
|
||||
s.cap = fresh.cap;
|
||||
s.len = fresh.len;
|
||||
// Ownership transferred to `s` — clear `fresh` so auto-Drop does not free twice
|
||||
fresh.entries = null as *SetEntry<T>;
|
||||
fresh.cap = 0;
|
||||
fresh.len = 0;
|
||||
return true;
|
||||
}
|
||||
bux_free(s.entries as *void);
|
||||
s.entries = fresh.entries;
|
||||
s.cap = fresh.cap;
|
||||
s.len = fresh.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
func Set_Clear<T>(s: *Set<T>) {
|
||||
var i: uint = 0;
|
||||
while i < s.cap {
|
||||
s.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
func Set_Clear<T>(s: *Set<T>) {
|
||||
var i: uint = 0;
|
||||
while i < s.cap {
|
||||
s.entries[i].occupied = false;
|
||||
i = i + 1;
|
||||
}
|
||||
s.len = 0;
|
||||
}
|
||||
s.len = 0;
|
||||
}
|
||||
|
||||
func Set_Free<T>(s: *Set<T>) {
|
||||
bux_free(s.entries as *void);
|
||||
s.entries = null as *SetEntry<T>;
|
||||
s.cap = 0;
|
||||
s.len = 0;
|
||||
}
|
||||
func Set_Free<T>(s: *Set<T>) {
|
||||
bux_free(s.entries as *void);
|
||||
s.entries = null as *SetEntry<T>;
|
||||
s.cap = 0;
|
||||
s.len = 0;
|
||||
}
|
||||
|
||||
func Set_Drop<T>(s: *Set<T>) {
|
||||
Set_Free<T>(s);
|
||||
}
|
||||
func Set_Drop<T>(s: *Set<T>) {
|
||||
Set_Free<T>(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-28
@@ -1,39 +1,39 @@
|
||||
module Std::Slice {
|
||||
|
||||
extern func bux_bounds_check(index: uint, len: uint);
|
||||
extern func bux_bounds_check(index: uint, len: uint);
|
||||
|
||||
struct Slice<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
}
|
||||
struct Slice<T> {
|
||||
data: *T,
|
||||
len: uint,
|
||||
}
|
||||
|
||||
func Slice_FromArray<T>(arr: *Array<T>) -> Slice<T> {
|
||||
var s: Slice<T>;
|
||||
s.data = arr.data;
|
||||
s.len = arr.len;
|
||||
return s;
|
||||
}
|
||||
func Slice_FromArray<T>(arr: *Array<T>) -> Slice<T> {
|
||||
var s: Slice<T>;
|
||||
s.data = arr.data;
|
||||
s.len = arr.len;
|
||||
return s;
|
||||
}
|
||||
|
||||
func Slice_Get<T>(self: *Slice<T>, idx: uint) -> T {
|
||||
bux_bounds_check(idx, self.len);
|
||||
return self.data[idx];
|
||||
}
|
||||
func Slice_Get<T>(self: *Slice<T>, idx: uint) -> T {
|
||||
bux_bounds_check(idx, self.len);
|
||||
return self.data[idx];
|
||||
}
|
||||
|
||||
func Slice_Set<T>(self: *Slice<T>, idx: uint, value: T) {
|
||||
bux_bounds_check(idx, self.len);
|
||||
self.data[idx] = value;
|
||||
}
|
||||
func Slice_Set<T>(self: *Slice<T>, idx: uint, value: T) {
|
||||
bux_bounds_check(idx, self.len);
|
||||
self.data[idx] = value;
|
||||
}
|
||||
|
||||
func Slice_Len<T>(self: *Slice<T>) -> uint {
|
||||
return self.len;
|
||||
}
|
||||
func Slice_Len<T>(self: *Slice<T>) -> uint {
|
||||
return self.len;
|
||||
}
|
||||
|
||||
func Slice_operator_index_get<T>(self: *Slice<T>, idx: uint) -> T {
|
||||
return Slice_Get<T>(self, idx);
|
||||
}
|
||||
func Slice_operator_index_get<T>(self: *Slice<T>, idx: uint) -> T {
|
||||
return Slice_Get<T>(self, idx);
|
||||
}
|
||||
|
||||
func Slice_operator_index_set<T>(self: *Slice<T>, idx: uint, value: T) {
|
||||
Slice_Set<T>(self, idx, value);
|
||||
}
|
||||
func Slice_operator_index_set<T>(self: *Slice<T>, idx: uint, value: T) {
|
||||
Slice_Set<T>(self, idx, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+270
-261
@@ -1,288 +1,297 @@
|
||||
module Std::String {
|
||||
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_strcmp(a: String, b: String) -> int;
|
||||
extern func bux_strncmp(a: String, b: String, n: uint) -> int;
|
||||
extern func bux_strcpy(dest: *char8, src: String) -> *char8;
|
||||
extern func bux_strcat(dest: *char8, src: String) -> *char8;
|
||||
extern func bux_strncpy(dest: *char8, src: String, n: uint) -> *char8;
|
||||
extern func bux_strstr(haystack: String, needle: String) -> String;
|
||||
extern func bux_str_contains(haystack: String, needle: String) -> int;
|
||||
extern func bux_str_offset(pos: String, base: String) -> uint;
|
||||
extern func bux_str_is_null(s: String) -> int;
|
||||
extern func bux_str_slice(s: String, start: uint, len: uint) -> String;
|
||||
extern func bux_str_trim_left(s: String) -> String;
|
||||
extern func bux_str_trim_right(s: String) -> String;
|
||||
extern func bux_str_trim(s: String) -> String;
|
||||
extern func bux_int_to_str(n: int64) -> String;
|
||||
extern func bux_str_to_int(s: String) -> int64;
|
||||
extern func bux_sb_new(initial_cap: uint) -> *void;
|
||||
extern func bux_sb_append(sb: *void, s: String);
|
||||
extern func bux_sb_append_int(sb: *void, n: int64);
|
||||
extern func bux_sb_append_float(sb: *void, f: float64);
|
||||
extern func bux_sb_append_char(sb: *void, c: char8);
|
||||
extern func bux_sb_build(sb: *void) -> String;
|
||||
extern func bux_sb_free(sb: *void);
|
||||
extern func bux_str_split_count(s: String, delim: String) -> uint;
|
||||
extern func bux_str_split_part(s: String, delim: String, index: uint) -> String;
|
||||
extern func bux_str_join2(a: String, b: String, sep: String) -> String;
|
||||
extern func bux_float_to_string(f: float64) -> String;
|
||||
extern func bux_str_format(pattern: String, a0: String, a1: String, a2: String, a3: String, a4: String, a5: String, a6: String, a7: String) -> String;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_strcmp(a: String, b: String) -> int;
|
||||
extern func bux_strncmp(a: String, b: String, n: uint) -> int;
|
||||
extern func bux_strcpy(dest: *char8, src: String) -> *char8;
|
||||
extern func bux_strcat(dest: *char8, src: String) -> *char8;
|
||||
extern func bux_strncpy(dest: *char8, src: String, n: uint) -> *char8;
|
||||
extern func bux_strstr(haystack: String, needle: String) -> String;
|
||||
extern func bux_str_contains(haystack: String, needle: String) -> int;
|
||||
extern func bux_str_offset(pos: String, base: String) -> uint;
|
||||
extern func bux_str_is_null(s: String) -> int;
|
||||
extern func bux_str_slice(s: String, start: uint, len: uint) -> String;
|
||||
extern func bux_str_trim_left(s: String) -> String;
|
||||
extern func bux_str_trim_right(s: String) -> String;
|
||||
extern func bux_str_trim(s: String) -> String;
|
||||
extern func bux_int_to_str(n: int64) -> String;
|
||||
extern func bux_str_to_int(s: String) -> int64;
|
||||
extern func bux_sb_new(initial_cap: uint) -> *void;
|
||||
extern func bux_sb_append(sb: *void, s: String);
|
||||
extern func bux_sb_append_int(sb: *void, n: int64);
|
||||
extern func bux_sb_append_float(sb: *void, f: float64);
|
||||
extern func bux_sb_append_char(sb: *void, c: char8);
|
||||
extern func bux_sb_build(sb: *void) -> String;
|
||||
extern func bux_sb_free(sb: *void);
|
||||
extern func bux_str_split_count(s: String, delim: String) -> uint;
|
||||
extern func bux_str_split_part(s: String, delim: String, index: uint) -> String;
|
||||
extern func bux_str_join2(a: String, b: String, sep: String) -> String;
|
||||
extern func bux_float_to_string(f: float64) -> String;
|
||||
extern func bux_str_format(pattern: String, a0: String, a1: String, a2: String, a3: String, a4: String, a5: String, a6: String, a7: String) -> String;
|
||||
|
||||
|
||||
func String_Len(s: String) -> uint {
|
||||
return bux_strlen(s);
|
||||
}
|
||||
|
||||
func String_IsEmpty(s: String) -> bool {
|
||||
return bux_strlen(s) == 0;
|
||||
}
|
||||
|
||||
func String_IsNull(s: String) -> bool {
|
||||
return bux_str_is_null(s) != 0;
|
||||
}
|
||||
|
||||
func String_Eq(a: String, b: String) -> bool {
|
||||
return bux_strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
func String_Concat(a: String, b: String) -> String {
|
||||
let len_a: uint = bux_strlen(a);
|
||||
let len_b: uint = bux_strlen(b);
|
||||
let total: uint = len_a + len_b + 1;
|
||||
let buf: *char8 = bux_alloc(total) as *char8;
|
||||
bux_strcpy(buf, a);
|
||||
bux_strcat(buf, b);
|
||||
return buf;
|
||||
}
|
||||
|
||||
func String_Copy(s: String) -> String {
|
||||
let len: uint = bux_strlen(s);
|
||||
let buf: *char8 = bux_alloc(len + 1) as *char8;
|
||||
bux_strcpy(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
func String_StartsWith(s: String, prefix: String) -> bool {
|
||||
let s_len: uint = bux_strlen(s);
|
||||
let p_len: uint = bux_strlen(prefix);
|
||||
if p_len > s_len {
|
||||
return false;
|
||||
/// Byte length of a C string (`strlen`).
|
||||
func String_Len(s: String) -> uint {
|
||||
return bux_strlen(s);
|
||||
}
|
||||
let r: int = bux_strncmp(s, prefix, p_len);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
func String_EndsWith(s: String, suffix: String) -> bool {
|
||||
let s_len: uint = bux_strlen(s);
|
||||
let suf_len: uint = bux_strlen(suffix);
|
||||
if suf_len > s_len {
|
||||
return false;
|
||||
/// True if the string has zero length.
|
||||
func String_IsEmpty(s: String) -> bool {
|
||||
return bux_strlen(s) == 0;
|
||||
}
|
||||
let start: uint = s_len - suf_len;
|
||||
let tail: String = bux_str_slice(s, start, suf_len);
|
||||
let eq: bool = bux_strcmp(tail, suffix) == 0;
|
||||
return eq;
|
||||
}
|
||||
|
||||
func String_Contains(s: String, substr: String) -> bool {
|
||||
let r: int = bux_str_contains(s, substr);
|
||||
return r != 0;
|
||||
}
|
||||
/// True if the pointer is null.
|
||||
func String_IsNull(s: String) -> bool {
|
||||
return bux_str_is_null(s) != 0;
|
||||
}
|
||||
|
||||
func String_Slice(s: String, start: uint, len: uint) -> String {
|
||||
return bux_str_slice(s, start, len);
|
||||
}
|
||||
/// Lexicographic equality.
|
||||
func String_Eq(a: String, b: String) -> bool {
|
||||
return bux_strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
func String_Trim(s: String) -> String {
|
||||
return bux_str_trim(s);
|
||||
}
|
||||
/// Allocate and return `a` concatenated with `b`.
|
||||
func String_Concat(a: String, b: String) -> String {
|
||||
let len_a: uint = bux_strlen(a);
|
||||
let len_b: uint = bux_strlen(b);
|
||||
let total: uint = len_a + len_b + 1;
|
||||
let buf: *char8 = bux_alloc(total) as *char8;
|
||||
bux_strcpy(buf, a);
|
||||
bux_strcat(buf, b);
|
||||
return buf;
|
||||
}
|
||||
|
||||
func String_TrimLeft(s: String) -> String {
|
||||
return bux_str_trim_left(s);
|
||||
}
|
||||
/// Heap-copy of `s`.
|
||||
func String_Copy(s: String) -> String {
|
||||
let len: uint = bux_strlen(s);
|
||||
let buf: *char8 = bux_alloc(len + 1) as *char8;
|
||||
bux_strcpy(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
func String_TrimRight(s: String) -> String {
|
||||
return bux_str_trim_right(s);
|
||||
}
|
||||
|
||||
func String_FromInt(n: int64) -> String {
|
||||
return bux_int_to_str(n);
|
||||
}
|
||||
|
||||
func String_ToInt(s: String) -> int64 {
|
||||
return bux_str_to_int(s);
|
||||
}
|
||||
|
||||
// String Builder — efficient string construction
|
||||
struct StringBuilder {
|
||||
handle: *void,
|
||||
}
|
||||
|
||||
func StringBuilder_New() -> StringBuilder {
|
||||
return StringBuilder { handle: bux_sb_new(64) };
|
||||
}
|
||||
|
||||
func StringBuilder_NewCap(cap: uint) -> StringBuilder {
|
||||
return StringBuilder { handle: bux_sb_new(cap) };
|
||||
}
|
||||
|
||||
func StringBuilder_Append(sb: *StringBuilder, s: String) {
|
||||
bux_sb_append(sb.handle, s);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendInt(sb: *StringBuilder, n: int64) {
|
||||
bux_sb_append_int(sb.handle, n);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendFloat(sb: *StringBuilder, f: float64) {
|
||||
bux_sb_append_float(sb.handle, f);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendChar(sb: *StringBuilder, c: char8) {
|
||||
bux_sb_append_char(sb.handle, c);
|
||||
}
|
||||
|
||||
func StringBuilder_Build(sb: *StringBuilder) -> String {
|
||||
return bux_sb_build(sb.handle);
|
||||
}
|
||||
|
||||
func StringBuilder_Free(sb: *StringBuilder) {
|
||||
bux_sb_free(sb.handle);
|
||||
}
|
||||
|
||||
/* True if empty or only whitespace (space, tab, CR, LF) */
|
||||
func String_IsBlank(s: String) -> bool {
|
||||
let n: uint = bux_strlen(s);
|
||||
var i: uint = 0;
|
||||
while i < n {
|
||||
let ch: String = bux_str_slice(s, i, 1);
|
||||
if !(String_Eq(ch, " ") || String_Eq(ch, "\t") || String_Eq(ch, "\n") || String_Eq(ch, "\r")) {
|
||||
/// True if `s` begins with `prefix`.
|
||||
func String_StartsWith(s: String, prefix: String) -> bool {
|
||||
let s_len: uint = bux_strlen(s);
|
||||
let p_len: uint = bux_strlen(prefix);
|
||||
if p_len > s_len {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
let r: int = bux_strncmp(s, prefix, p_len);
|
||||
return r == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Repeat s, count times (count==0 → empty string) */
|
||||
func String_Repeat(s: String, count: uint) -> String {
|
||||
if count == 0 {
|
||||
return "";
|
||||
}
|
||||
if count == 1 {
|
||||
return s;
|
||||
}
|
||||
var sb: StringBuilder = StringBuilder_New();
|
||||
var i: uint = 0;
|
||||
while i < count {
|
||||
StringBuilder_Append(&sb, s);
|
||||
i = i + 1;
|
||||
}
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// String split/join
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func String_SplitCount(s: String, delim: String) -> uint {
|
||||
return bux_str_split_count(s, delim);
|
||||
}
|
||||
|
||||
func String_SplitPart(s: String, delim: String, index: uint) -> String {
|
||||
return bux_str_split_part(s, delim, index);
|
||||
}
|
||||
|
||||
func String_Join2(a: String, b: String, sep: String) -> String {
|
||||
return bux_str_join2(a, b, sep);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// String find/replace/format
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// String_Chars — return single-character string at index (for iteration)
|
||||
func String_Chars(s: String, index: uint) -> String {
|
||||
return bux_str_slice(s, index, 1);
|
||||
}
|
||||
|
||||
func String_Find(haystack: String, needle: String) -> String {
|
||||
return bux_strstr(haystack, needle);
|
||||
}
|
||||
|
||||
func String_Offset(pos: String, base: String) -> uint {
|
||||
return bux_str_offset(pos, base);
|
||||
}
|
||||
|
||||
func String_Replace(s: String, old: String, new: String) -> String {
|
||||
let pos: String = bux_strstr(s, old);
|
||||
if String_IsNull(pos) {
|
||||
return s;
|
||||
}
|
||||
let oldLen: uint = bux_strlen(old);
|
||||
let prefixLen: uint = String_Offset(pos, s);
|
||||
let prefix: String = bux_str_slice(s, 0, prefixLen);
|
||||
let suffix: String = bux_str_slice(s, prefixLen + oldLen, bux_strlen(s) - prefixLen - oldLen);
|
||||
let temp: String = String_Concat(prefix, new);
|
||||
let result: String = String_Concat(temp, suffix);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Replace every non-overlapping occurrence of old with new.
|
||||
Empty old is a no-op (returns s unchanged). Safe if new contains old. */
|
||||
func String_ReplaceAll(s: String, old: String, new: String) -> String {
|
||||
let oldLen: uint = bux_strlen(old);
|
||||
if oldLen == 0 {
|
||||
return s;
|
||||
}
|
||||
var sb: StringBuilder = StringBuilder_New();
|
||||
var remaining: String = s;
|
||||
while true {
|
||||
let pos: String = bux_strstr(remaining, old);
|
||||
if String_IsNull(pos) {
|
||||
StringBuilder_Append(&sb, remaining);
|
||||
break;
|
||||
/// True if `s` ends with `suffix`.
|
||||
func String_EndsWith(s: String, suffix: String) -> bool {
|
||||
let s_len: uint = bux_strlen(s);
|
||||
let suf_len: uint = bux_strlen(suffix);
|
||||
if suf_len > s_len {
|
||||
return false;
|
||||
}
|
||||
let prefixLen: uint = String_Offset(pos, remaining);
|
||||
let prefix: String = bux_str_slice(remaining, 0, prefixLen);
|
||||
StringBuilder_Append(&sb, prefix);
|
||||
StringBuilder_Append(&sb, new);
|
||||
let remLen: uint = bux_strlen(remaining);
|
||||
remaining = bux_str_slice(remaining, prefixLen + oldLen, remLen - prefixLen - oldLen);
|
||||
let start: uint = s_len - suf_len;
|
||||
let tail: String = bux_str_slice(s, start, suf_len);
|
||||
let eq: bool = bux_strcmp(tail, suffix) == 0;
|
||||
return eq;
|
||||
}
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern func bux_str_to_float(s: String) -> float64;
|
||||
/// True if `substr` occurs anywhere in `s`.
|
||||
func String_Contains(s: String, substr: String) -> bool {
|
||||
let r: int = bux_str_contains(s, substr);
|
||||
return r != 0;
|
||||
}
|
||||
|
||||
func String_ToFloat(s: String) -> float64 {
|
||||
return bux_str_to_float(s);
|
||||
}
|
||||
func String_Slice(s: String, start: uint, len: uint) -> String {
|
||||
return bux_str_slice(s, start, len);
|
||||
}
|
||||
|
||||
func String_FromBool(b: bool) -> String {
|
||||
if b { return "true"; }
|
||||
return "false";
|
||||
}
|
||||
func String_Trim(s: String) -> String {
|
||||
return bux_str_trim(s);
|
||||
}
|
||||
|
||||
func String_FromFloat(f: float64) -> String {
|
||||
return bux_float_to_string(f);
|
||||
}
|
||||
func String_TrimLeft(s: String) -> String {
|
||||
return bux_str_trim_left(s);
|
||||
}
|
||||
|
||||
func String_Format1(pattern: String, a0: String) -> String {
|
||||
return bux_str_format(pattern, a0, "", "", "", "", "", "", "");
|
||||
}
|
||||
func String_TrimRight(s: String) -> String {
|
||||
return bux_str_trim_right(s);
|
||||
}
|
||||
|
||||
func String_Format2(pattern: String, a0: String, a1: String) -> String {
|
||||
return bux_str_format(pattern, a0, a1, "", "", "", "", "", "");
|
||||
}
|
||||
func String_FromInt(n: int64) -> String {
|
||||
return bux_int_to_str(n);
|
||||
}
|
||||
|
||||
func String_Format3(pattern: String, a0: String, a1: String, a2: String) -> String {
|
||||
return bux_str_format(pattern, a0, a1, a2, "", "", "", "", "");
|
||||
}
|
||||
func String_ToInt(s: String) -> int64 {
|
||||
return bux_str_to_int(s);
|
||||
}
|
||||
|
||||
// String Builder — efficient string construction
|
||||
struct StringBuilder {
|
||||
handle: *void,
|
||||
}
|
||||
|
||||
func StringBuilder_New() -> StringBuilder {
|
||||
return StringBuilder { handle: bux_sb_new(64) };
|
||||
}
|
||||
|
||||
func StringBuilder_NewCap(cap: uint) -> StringBuilder {
|
||||
return StringBuilder { handle: bux_sb_new(cap) };
|
||||
}
|
||||
|
||||
func StringBuilder_Append(sb: *StringBuilder, s: String) {
|
||||
bux_sb_append(sb.handle, s);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendInt(sb: *StringBuilder, n: int64) {
|
||||
bux_sb_append_int(sb.handle, n);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendFloat(sb: *StringBuilder, f: float64) {
|
||||
bux_sb_append_float(sb.handle, f);
|
||||
}
|
||||
|
||||
func StringBuilder_AppendChar(sb: *StringBuilder, c: char8) {
|
||||
bux_sb_append_char(sb.handle, c);
|
||||
}
|
||||
|
||||
func StringBuilder_Build(sb: *StringBuilder) -> String {
|
||||
return bux_sb_build(sb.handle);
|
||||
}
|
||||
|
||||
func StringBuilder_Free(sb: *StringBuilder) {
|
||||
bux_sb_free(sb.handle);
|
||||
}
|
||||
|
||||
/// True if empty or only whitespace (space, tab, CR, LF).
|
||||
func String_IsBlank(s: String) -> bool {
|
||||
let n: uint = bux_strlen(s);
|
||||
var i: uint = 0;
|
||||
while i < n {
|
||||
let ch: String = bux_str_slice(s, i, 1);
|
||||
if !(String_Eq(ch, " ") || String_Eq(ch, "\t") || String_Eq(ch, "\n") || String_Eq(ch, "\r")) {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Repeat `s`, `count` times (`count == 0` → empty string).
|
||||
func String_Repeat(s: String, count: uint) -> String {
|
||||
if count == 0 {
|
||||
return "";
|
||||
}
|
||||
if count == 1 {
|
||||
return s;
|
||||
}
|
||||
var sb: StringBuilder = StringBuilder_New();
|
||||
var i: uint = 0;
|
||||
while i < count {
|
||||
StringBuilder_Append(&sb, s);
|
||||
i = i + 1;
|
||||
}
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// String split/join
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func String_SplitCount(s: String, delim: String) -> uint {
|
||||
return bux_str_split_count(s, delim);
|
||||
}
|
||||
|
||||
func String_SplitPart(s: String, delim: String, index: uint) -> String {
|
||||
return bux_str_split_part(s, delim, index);
|
||||
}
|
||||
|
||||
func String_Join2(a: String, b: String, sep: String) -> String {
|
||||
return bux_str_join2(a, b, sep);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// String find/replace/format
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// String_Chars — return single-character string at index (for iteration)
|
||||
func String_Chars(s: String, index: uint) -> String {
|
||||
return bux_str_slice(s, index, 1);
|
||||
}
|
||||
|
||||
func String_Find(haystack: String, needle: String) -> String {
|
||||
return bux_strstr(haystack, needle);
|
||||
}
|
||||
|
||||
func String_Offset(pos: String, base: String) -> uint {
|
||||
return bux_str_offset(pos, base);
|
||||
}
|
||||
|
||||
func String_Replace(s: String, old: String, new: String) -> String {
|
||||
let pos: String = bux_strstr(s, old);
|
||||
if String_IsNull(pos) {
|
||||
return s;
|
||||
}
|
||||
let oldLen: uint = bux_strlen(old);
|
||||
let prefixLen: uint = String_Offset(pos, s);
|
||||
let prefix: String = bux_str_slice(s, 0, prefixLen);
|
||||
let suffix: String = bux_str_slice(s, prefixLen + oldLen, bux_strlen(s) - prefixLen - oldLen);
|
||||
let temp: String = String_Concat(prefix, new);
|
||||
let result: String = String_Concat(temp, suffix);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Replace every non-overlapping occurrence of `old` with `new`.
|
||||
/// Empty `old` is a no-op (returns `s` unchanged). Safe if `new` contains `old`.
|
||||
func String_ReplaceAll(s: String, old: String, new: String) -> String {
|
||||
let oldLen: uint = bux_strlen(old);
|
||||
if oldLen == 0 {
|
||||
return s;
|
||||
}
|
||||
var sb: StringBuilder = StringBuilder_New();
|
||||
var remaining: String = s;
|
||||
while true {
|
||||
let pos: String = bux_strstr(remaining, old);
|
||||
if String_IsNull(pos) {
|
||||
StringBuilder_Append(&sb, remaining);
|
||||
break;
|
||||
}
|
||||
let prefixLen: uint = String_Offset(pos, remaining);
|
||||
let prefix: String = bux_str_slice(remaining, 0, prefixLen);
|
||||
StringBuilder_Append(&sb, prefix);
|
||||
StringBuilder_Append(&sb, new);
|
||||
let remLen: uint = bux_strlen(remaining);
|
||||
remaining = bux_str_slice(remaining, prefixLen + oldLen, remLen - prefixLen - oldLen);
|
||||
}
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern func bux_str_to_float(s: String) -> float64;
|
||||
|
||||
func String_ToFloat(s: String) -> float64 {
|
||||
return bux_str_to_float(s);
|
||||
}
|
||||
|
||||
func String_FromBool(b: bool) -> String {
|
||||
if b { return "true"; }
|
||||
return "false";
|
||||
}
|
||||
|
||||
func String_FromFloat(f: float64) -> String {
|
||||
return bux_float_to_string(f);
|
||||
}
|
||||
|
||||
func String_Format1(pattern: String, a0: String) -> String {
|
||||
return bux_str_format(pattern, a0, "", "", "", "", "", "", "");
|
||||
}
|
||||
|
||||
func String_Format2(pattern: String, a0: String, a1: String) -> String {
|
||||
return bux_str_format(pattern, a0, a1, "", "", "", "", "", "");
|
||||
}
|
||||
|
||||
func String_Format3(pattern: String, a0: String, a1: String, a2: String) -> String {
|
||||
return bux_str_format(pattern, a0, a1, a2, "", "", "", "", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-42
@@ -1,58 +1,58 @@
|
||||
module Std::Sync {
|
||||
|
||||
extern func bux_mutex_new() -> *void;
|
||||
extern func bux_mutex_lock(handle: *void);
|
||||
extern func bux_mutex_unlock(handle: *void);
|
||||
extern func bux_mutex_free(handle: *void);
|
||||
extern func bux_mutex_new() -> *void;
|
||||
extern func bux_mutex_lock(handle: *void);
|
||||
extern func bux_mutex_unlock(handle: *void);
|
||||
extern func bux_mutex_free(handle: *void);
|
||||
|
||||
extern func bux_rwlock_new() -> *void;
|
||||
extern func bux_rwlock_rdlock(handle: *void);
|
||||
extern func bux_rwlock_wrlock(handle: *void);
|
||||
extern func bux_rwlock_unlock(handle: *void);
|
||||
extern func bux_rwlock_free(handle: *void);
|
||||
extern func bux_rwlock_new() -> *void;
|
||||
extern func bux_rwlock_rdlock(handle: *void);
|
||||
extern func bux_rwlock_wrlock(handle: *void);
|
||||
extern func bux_rwlock_unlock(handle: *void);
|
||||
extern func bux_rwlock_free(handle: *void);
|
||||
|
||||
struct Mutex {
|
||||
handle: *void;
|
||||
}
|
||||
struct Mutex {
|
||||
handle: *void;
|
||||
}
|
||||
|
||||
struct RwLock {
|
||||
handle: *void;
|
||||
}
|
||||
struct RwLock {
|
||||
handle: *void;
|
||||
}
|
||||
|
||||
func Mutex_New() -> Mutex {
|
||||
return Mutex { handle: bux_mutex_new() };
|
||||
}
|
||||
func Mutex_New() -> Mutex {
|
||||
return Mutex { handle: bux_mutex_new() };
|
||||
}
|
||||
|
||||
func Mutex_Lock(m: *Mutex) {
|
||||
bux_mutex_lock(m.handle);
|
||||
}
|
||||
func Mutex_Lock(m: *Mutex) {
|
||||
bux_mutex_lock(m.handle);
|
||||
}
|
||||
|
||||
func Mutex_Unlock(m: *Mutex) {
|
||||
bux_mutex_unlock(m.handle);
|
||||
}
|
||||
func Mutex_Unlock(m: *Mutex) {
|
||||
bux_mutex_unlock(m.handle);
|
||||
}
|
||||
|
||||
func Mutex_Free(m: *Mutex) {
|
||||
bux_mutex_free(m.handle);
|
||||
}
|
||||
func Mutex_Free(m: *Mutex) {
|
||||
bux_mutex_free(m.handle);
|
||||
}
|
||||
|
||||
func RwLock_New() -> RwLock {
|
||||
return RwLock { handle: bux_rwlock_new() };
|
||||
}
|
||||
func RwLock_New() -> RwLock {
|
||||
return RwLock { handle: bux_rwlock_new() };
|
||||
}
|
||||
|
||||
func RwLock_ReadLock(rw: *RwLock) {
|
||||
bux_rwlock_rdlock(rw.handle);
|
||||
}
|
||||
func RwLock_ReadLock(rw: *RwLock) {
|
||||
bux_rwlock_rdlock(rw.handle);
|
||||
}
|
||||
|
||||
func RwLock_WriteLock(rw: *RwLock) {
|
||||
bux_rwlock_wrlock(rw.handle);
|
||||
}
|
||||
func RwLock_WriteLock(rw: *RwLock) {
|
||||
bux_rwlock_wrlock(rw.handle);
|
||||
}
|
||||
|
||||
func RwLock_Unlock(rw: *RwLock) {
|
||||
bux_rwlock_unlock(rw.handle);
|
||||
}
|
||||
func RwLock_Unlock(rw: *RwLock) {
|
||||
bux_rwlock_unlock(rw.handle);
|
||||
}
|
||||
|
||||
func RwLock_Free(rw: *RwLock) {
|
||||
bux_rwlock_free(rw.handle);
|
||||
}
|
||||
func RwLock_Free(rw: *RwLock) {
|
||||
bux_rwlock_free(rw.handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-31
@@ -1,43 +1,43 @@
|
||||
module Std::Task {
|
||||
|
||||
extern func bux_task_init(num_workers: int);
|
||||
extern func bux_task_spawn(fn: *void, arg: *void) -> *void;
|
||||
extern func bux_task_join(handle: *void);
|
||||
extern func bux_task_sleep(ms: int64);
|
||||
extern func bux_task_yield();
|
||||
extern func bux_task_current_id() -> int;
|
||||
extern func bux_task_shutdown();
|
||||
extern func bux_task_init(num_workers: int);
|
||||
extern func bux_task_spawn(fn: *void, arg: *void) -> *void;
|
||||
extern func bux_task_join(handle: *void);
|
||||
extern func bux_task_sleep(ms: int64);
|
||||
extern func bux_task_yield();
|
||||
extern func bux_task_current_id() -> int;
|
||||
extern func bux_task_shutdown();
|
||||
|
||||
struct TaskHandle {
|
||||
handle: *void;
|
||||
}
|
||||
struct TaskHandle {
|
||||
handle: *void;
|
||||
}
|
||||
|
||||
func Task_Init(num_workers: int) {
|
||||
bux_task_init(num_workers);
|
||||
}
|
||||
func Task_Init(num_workers: int) {
|
||||
bux_task_init(num_workers);
|
||||
}
|
||||
|
||||
func Task_Spawn(fn: *void, arg: *void) -> TaskHandle {
|
||||
return TaskHandle { handle: bux_task_spawn(fn, arg) };
|
||||
}
|
||||
func Task_Spawn(fn: *void, arg: *void) -> TaskHandle {
|
||||
return TaskHandle { handle: bux_task_spawn(fn, arg) };
|
||||
}
|
||||
|
||||
func Task_Wait(t: TaskHandle) {
|
||||
bux_task_join(t.handle);
|
||||
}
|
||||
func Task_Wait(t: TaskHandle) {
|
||||
bux_task_join(t.handle);
|
||||
}
|
||||
|
||||
func Task_Sleep(ms: int64) {
|
||||
bux_task_sleep(ms);
|
||||
}
|
||||
func Task_Sleep(ms: int64) {
|
||||
bux_task_sleep(ms);
|
||||
}
|
||||
|
||||
func Task_Yield() {
|
||||
bux_task_yield();
|
||||
}
|
||||
func Task_Yield() {
|
||||
bux_task_yield();
|
||||
}
|
||||
|
||||
func Task_CurrentId() -> int {
|
||||
return bux_task_current_id();
|
||||
}
|
||||
func Task_CurrentId() -> int {
|
||||
return bux_task_current_id();
|
||||
}
|
||||
|
||||
func Task_Shutdown() {
|
||||
bux_task_shutdown();
|
||||
}
|
||||
func Task_Shutdown() {
|
||||
bux_task_shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+75
-65
@@ -1,76 +1,86 @@
|
||||
module Std::Test {
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Std::String::{String_Eq};
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Std::String::{String_Eq};
|
||||
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_assert(cond: int, file: String, line: int, expr: String);
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_assert(cond: int, file: String, line: int, expr: String);
|
||||
|
||||
func Test_Exit(code: int) {
|
||||
bux_exit(code);
|
||||
}
|
||||
/// Exit the process with `code` (for test runners).
|
||||
func Test_Exit(code: int) {
|
||||
bux_exit(code);
|
||||
}
|
||||
|
||||
func Test_Assert(cond: bool) {
|
||||
bux_assert(cond as int, "", 0, "");
|
||||
}
|
||||
/// Assert `cond` is true; abort on failure.
|
||||
func Test_Assert(cond: bool) {
|
||||
bux_assert(cond as int, "", 0, "");
|
||||
}
|
||||
|
||||
func Test_AssertEqInt(a: int, b: int) {
|
||||
if a != b {
|
||||
PrintLine("ASSERT_EQ_INT FAILED:");
|
||||
PrintInt(a);
|
||||
PrintLine(" != ");
|
||||
PrintInt(b);
|
||||
/// Assert two ints are equal; print both values and exit 1 on mismatch.
|
||||
func Test_AssertEqInt(a: int, b: int) {
|
||||
if a != b {
|
||||
PrintLine("ASSERT_EQ_INT FAILED:");
|
||||
PrintInt(a);
|
||||
PrintLine(" != ");
|
||||
PrintInt(b);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert two ints differ.
|
||||
func Test_AssertNeqInt(a: int, b: int) {
|
||||
if a == b {
|
||||
PrintLine("ASSERT_NEQ_INT FAILED: both are");
|
||||
PrintInt(a);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert two strings are equal (`String_Eq`).
|
||||
func Test_AssertEqString(a: String, b: String) {
|
||||
if !String_Eq(a, b) {
|
||||
PrintLine("ASSERT_EQ_STRING FAILED:");
|
||||
PrintLine(a);
|
||||
PrintLine(" != ");
|
||||
PrintLine(b);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert two bools are equal.
|
||||
func Test_AssertEqBool(a: bool, b: bool) {
|
||||
if a != b {
|
||||
PrintLine("ASSERT_EQ_BOOL FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert `cond` is true.
|
||||
func Test_AssertTrue(cond: bool) {
|
||||
if !cond {
|
||||
PrintLine("ASSERT_TRUE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert `cond` is false.
|
||||
func Test_AssertFalse(cond: bool) {
|
||||
if cond {
|
||||
PrintLine("ASSERT_FALSE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fail the test with a message and exit 1.
|
||||
func Test_Fail(msg: String) {
|
||||
PrintLine("FAIL:");
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertNeqInt(a: int, b: int) {
|
||||
if a == b {
|
||||
PrintLine("ASSERT_NEQ_INT FAILED: both are");
|
||||
PrintInt(a);
|
||||
bux_exit(1);
|
||||
/// Print a PASS line (for human-readable runners / goldens).
|
||||
func Test_Pass(msg: String) {
|
||||
PrintLine("PASS:");
|
||||
PrintLine(msg);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertEqString(a: String, b: String) {
|
||||
if !String_Eq(a, b) {
|
||||
PrintLine("ASSERT_EQ_STRING FAILED:");
|
||||
PrintLine(a);
|
||||
PrintLine(" != ");
|
||||
PrintLine(b);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertEqBool(a: bool, b: bool) {
|
||||
if a != b {
|
||||
PrintLine("ASSERT_EQ_BOOL FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertTrue(cond: bool) {
|
||||
if !cond {
|
||||
PrintLine("ASSERT_TRUE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertFalse(cond: bool) {
|
||||
if cond {
|
||||
PrintLine("ASSERT_FALSE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Fail(msg: String) {
|
||||
PrintLine("FAIL:");
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
|
||||
func Test_Pass(msg: String) {
|
||||
PrintLine("PASS:");
|
||||
PrintLine(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,19 +1,19 @@
|
||||
module Std::Time {
|
||||
|
||||
extern func bux_time_ms() -> int64;
|
||||
extern func bux_time_us() -> int64;
|
||||
extern func bux_sleep_ms(ms: int64);
|
||||
extern func bux_time_ms() -> int64;
|
||||
extern func bux_time_us() -> int64;
|
||||
extern func bux_sleep_ms(ms: int64);
|
||||
|
||||
func Time_NowMs() -> int64 {
|
||||
return bux_time_ms();
|
||||
}
|
||||
func Time_NowMs() -> int64 {
|
||||
return bux_time_ms();
|
||||
}
|
||||
|
||||
func Time_NowUs() -> int64 {
|
||||
return bux_time_us();
|
||||
}
|
||||
func Time_NowUs() -> int64 {
|
||||
return bux_time_us();
|
||||
}
|
||||
|
||||
func Time_SleepMs(ms: int64) {
|
||||
bux_sleep_ms(ms);
|
||||
}
|
||||
func Time_SleepMs(ms: int64) {
|
||||
bux_sleep_ms(ms);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+49
-49
@@ -3,65 +3,65 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Aes {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_aes_256_cbc_encrypt(plain: String, plainlen: int, key: String, iv: String, outlen: *int) -> String;
|
||||
extern func bux_aes_256_cbc_decrypt(cipher: String, cipherlen: int, key: String, iv: String, outlen: *int) -> String;
|
||||
extern func bux_aes_256_gcm_encrypt(plain: String, plainlen: int, key: String, iv: String, tag: *void, outlen: *int) -> String;
|
||||
extern func bux_aes_256_gcm_decrypt(cipher: String, cipherlen: int, key: String, iv: String, tag: String, outlen: *int) -> String;
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_aes_256_cbc_encrypt(plain: String, plainlen: int, key: String, iv: String, outlen: *int) -> String;
|
||||
extern func bux_aes_256_cbc_decrypt(cipher: String, cipherlen: int, key: String, iv: String, outlen: *int) -> String;
|
||||
extern func bux_aes_256_gcm_encrypt(plain: String, plainlen: int, key: String, iv: String, tag: *void, outlen: *int) -> String;
|
||||
extern func bux_aes_256_gcm_decrypt(cipher: String, cipherlen: int, key: String, iv: String, tag: String, outlen: *int) -> String;
|
||||
|
||||
// --- AES-256-CBC ---
|
||||
// --- AES-256-CBC ---
|
||||
|
||||
const AES_KEY_SIZE: int = 32; // 256 bits
|
||||
const AES_IV_SIZE: int = 16; // 128 bits
|
||||
const AES_GCM_TAG_SIZE: int = 16;
|
||||
const AES_KEY_SIZE: int = 32; // 256 bits
|
||||
const AES_IV_SIZE: int = 16; // 128 bits
|
||||
const AES_GCM_TAG_SIZE: int = 16;
|
||||
|
||||
// Generate a random 256-bit AES key (returns raw 32 bytes)
|
||||
func Aes_GenerateKey() -> String {
|
||||
let buf: *void = Alloc(AES_KEY_SIZE as uint);
|
||||
if bux_random_bytes(buf, AES_KEY_SIZE) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
// Generate a random 256-bit AES key (returns raw 32 bytes)
|
||||
func Aes_GenerateKey() -> String {
|
||||
let buf: *void = Alloc(AES_KEY_SIZE as uint);
|
||||
if bux_random_bytes(buf, AES_KEY_SIZE) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
return buf as String;
|
||||
}
|
||||
return buf as String;
|
||||
}
|
||||
|
||||
// Generate a random 128-bit IV (returns raw 16 bytes)
|
||||
func Aes_GenerateIV() -> String {
|
||||
let buf: *void = Alloc(AES_IV_SIZE as uint);
|
||||
if bux_random_bytes(buf, AES_IV_SIZE) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
// Generate a random 128-bit IV (returns raw 16 bytes)
|
||||
func Aes_GenerateIV() -> String {
|
||||
let buf: *void = Alloc(AES_IV_SIZE as uint);
|
||||
if bux_random_bytes(buf, AES_IV_SIZE) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
return buf as String;
|
||||
}
|
||||
return buf as String;
|
||||
}
|
||||
|
||||
// AES-256-CBC encrypt. plain and key are binary strings, iv is 16 bytes.
|
||||
// Returns ciphertext (may be longer than plain due to PKCS#7 padding).
|
||||
func Aes_CbcEncrypt(plain: String, key: String, iv: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_cbc_encrypt(plain, String_Len(plain) as int, key, iv, &outlen);
|
||||
}
|
||||
// AES-256-CBC encrypt. plain and key are binary strings, iv is 16 bytes.
|
||||
// Returns ciphertext (may be longer than plain due to PKCS#7 padding).
|
||||
func Aes_CbcEncrypt(plain: String, key: String, iv: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_cbc_encrypt(plain, String_Len(plain) as int, key, iv, &outlen);
|
||||
}
|
||||
|
||||
// AES-256-CBC decrypt. Returns plaintext.
|
||||
func Aes_CbcDecrypt(cipher: String, key: String, iv: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_cbc_decrypt(cipher, String_Len(cipher) as int, key, iv, &outlen);
|
||||
}
|
||||
// AES-256-CBC decrypt. Returns plaintext.
|
||||
func Aes_CbcDecrypt(cipher: String, key: String, iv: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_cbc_decrypt(cipher, String_Len(cipher) as int, key, iv, &outlen);
|
||||
}
|
||||
|
||||
// --- AES-256-GCM (Authenticated Encryption) ---
|
||||
// --- AES-256-GCM (Authenticated Encryption) ---
|
||||
|
||||
// AES-256-GCM encrypt. Returns ciphertext. tag receives 16-byte authentication tag.
|
||||
func Aes_GcmEncrypt(plain: String, key: String, iv: String, tag: *void) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_gcm_encrypt(plain, String_Len(plain) as int, key, iv, tag, &outlen);
|
||||
}
|
||||
// AES-256-GCM encrypt. Returns ciphertext. tag receives 16-byte authentication tag.
|
||||
func Aes_GcmEncrypt(plain: String, key: String, iv: String, tag: *void) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_gcm_encrypt(plain, String_Len(plain) as int, key, iv, tag, &outlen);
|
||||
}
|
||||
|
||||
// AES-256-GCM decrypt. Returns plaintext. tag must be the 16-byte auth tag from encryption.
|
||||
func Aes_GcmDecrypt(cipher: String, key: String, iv: String, tag: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_gcm_decrypt(cipher, String_Len(cipher) as int, key, iv, tag, &outlen);
|
||||
}
|
||||
// AES-256-GCM decrypt. Returns plaintext. tag must be the 16-byte auth tag from encryption.
|
||||
func Aes_GcmDecrypt(cipher: String, key: String, iv: String, tag: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_aes_256_gcm_decrypt(cipher, String_Len(cipher) as int, key, iv, tag, &outlen);
|
||||
}
|
||||
}
|
||||
|
||||
+25
-25
@@ -3,32 +3,32 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Base64 {
|
||||
|
||||
import Std::String::{String_Len};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_base64url_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64url_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_base64url_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64url_decode(data: String, len: int, outlen: *int) -> String;
|
||||
|
||||
// --- Standard Base64 ---
|
||||
// --- Standard Base64 ---
|
||||
|
||||
func Base64_Encode(s: String) -> String {
|
||||
return bux_base64_encode(s, String_Len(s) as int);
|
||||
}
|
||||
|
||||
func Base64_Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
|
||||
// --- Base64URL (RFC 4648 §5, uses - and _ instead of + and /, no padding) ---
|
||||
|
||||
func Base64URL_Encode(s: String) -> String {
|
||||
return bux_base64url_encode(s, String_Len(s) as int);
|
||||
}
|
||||
|
||||
func Base64URL_Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64url_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
func Base64_Encode(s: String) -> String {
|
||||
return bux_base64_encode(s, String_Len(s) as int);
|
||||
}
|
||||
|
||||
func Base64_Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
|
||||
// --- Base64URL (RFC 4648 §5, uses - and _ instead of + and /, no padding) ---
|
||||
|
||||
func Base64URL_Encode(s: String) -> String {
|
||||
return bux_base64url_encode(s, String_Len(s) as int);
|
||||
}
|
||||
|
||||
func Base64URL_Decode(s: String) -> String {
|
||||
let outlen: int = 0;
|
||||
return bux_base64url_decode(s, String_Len(s) as int, &outlen);
|
||||
}
|
||||
}
|
||||
|
||||
+43
-43
@@ -3,56 +3,56 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Ecdsa {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
// Extern declarations for the runtime C implementations
|
||||
extern func bux_ecdsa_sign_p256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_ecdsa_verify_p256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_ecdsa_sign_p384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_ecdsa_verify_p384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
// Extern declarations for the runtime C implementations
|
||||
extern func bux_ecdsa_sign_p256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_ecdsa_verify_p256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_ecdsa_sign_p384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_ecdsa_verify_p384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
|
||||
func Ecdsa_SignP256(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_ecdsa_sign_p256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
func Ecdsa_SignP256(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_ecdsa_sign_p256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Ecdsa_SignP256Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Ecdsa_SignP256(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
func Ecdsa_SignP256Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Ecdsa_SignP256(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Ecdsa_VerifyP256(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_ecdsa_verify_p256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
func Ecdsa_VerifyP256(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_ecdsa_verify_p256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Ecdsa_VerifyP256Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Ecdsa_VerifyP256(pemPublicKey, data, sig);
|
||||
}
|
||||
func Ecdsa_VerifyP256Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Ecdsa_VerifyP256(pemPublicKey, data, sig);
|
||||
}
|
||||
|
||||
func Ecdsa_SignP384(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_ecdsa_sign_p384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
func Ecdsa_SignP384(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_ecdsa_sign_p384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Ecdsa_SignP384Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Ecdsa_SignP384(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
func Ecdsa_SignP384Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Ecdsa_SignP384(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Ecdsa_VerifyP384(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_ecdsa_verify_p384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
func Ecdsa_VerifyP384(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_ecdsa_verify_p384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Ecdsa_VerifyP384Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Ecdsa_VerifyP384(pemPublicKey, data, sig);
|
||||
}
|
||||
func Ecdsa_VerifyP384Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Ecdsa_VerifyP384(pemPublicKey, data, sig);
|
||||
}
|
||||
}
|
||||
|
||||
+59
-59
@@ -3,78 +3,78 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Ed25519 {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len, String_Concat};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len, String_Concat};
|
||||
|
||||
extern func bux_ed25519_keypair(pubKey: *void, privKey: *void) -> int;
|
||||
extern func bux_ed25519_sign(privKey: String, data: String, datalen: int, sig: *void) -> int;
|
||||
extern func bux_ed25519_verify(pubKey: String, sig: String, data: String, datalen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
extern func bux_ed25519_keypair(pubKey: *void, privKey: *void) -> int;
|
||||
extern func bux_ed25519_sign(privKey: String, data: String, datalen: int, sig: *void) -> int;
|
||||
extern func bux_ed25519_verify(pubKey: String, sig: String, data: String, datalen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
|
||||
const ED25519_PUBKEY_SIZE: int = 32;
|
||||
const ED25519_PRIVKEY_SIZE: int = 32;
|
||||
const ED25519_SIG_SIZE: int = 64;
|
||||
const ED25519_PUBKEY_SIZE: int = 32;
|
||||
const ED25519_PRIVKEY_SIZE: int = 32;
|
||||
const ED25519_SIG_SIZE: int = 64;
|
||||
|
||||
// --- Key Generation ---
|
||||
// --- Key Generation ---
|
||||
|
||||
// Ed25519_Keypair: generates a new keypair.
|
||||
// Returns true on success. pubKey and privKey receive 32-byte raw keys.
|
||||
func Ed25519_Keypair(pubKey: *void, privKey: *void) -> bool {
|
||||
let r: int = bux_ed25519_keypair(pubKey, privKey);
|
||||
return r == 1;
|
||||
}
|
||||
// Ed25519_Keypair: generates a new keypair.
|
||||
// Returns true on success. pubKey and privKey receive 32-byte raw keys.
|
||||
func Ed25519_Keypair(pubKey: *void, privKey: *void) -> bool {
|
||||
let r: int = bux_ed25519_keypair(pubKey, privKey);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
// Convenience: generate and return base64-encoded keypair
|
||||
func Ed25519_KeypairBase64() -> String {
|
||||
let pubBuf: *void = Alloc(ED25519_PUBKEY_SIZE as uint);
|
||||
let priv: *void = Alloc(ED25519_PRIVKEY_SIZE as uint);
|
||||
if bux_ed25519_keypair(pubBuf, priv) != 1 {
|
||||
// Convenience: generate and return base64-encoded keypair
|
||||
func Ed25519_KeypairBase64() -> String {
|
||||
let pubBuf: *void = Alloc(ED25519_PUBKEY_SIZE as uint);
|
||||
let priv: *void = Alloc(ED25519_PRIVKEY_SIZE as uint);
|
||||
if bux_ed25519_keypair(pubBuf, priv) != 1 {
|
||||
Free(pubBuf);
|
||||
Free(priv);
|
||||
return "";
|
||||
}
|
||||
// Return "pub_b64:priv_b64"
|
||||
let pubB64: String = bux_base64_encode(pubBuf as String, ED25519_PUBKEY_SIZE);
|
||||
let privB64: String = bux_base64_encode(priv as String, ED25519_PRIVKEY_SIZE);
|
||||
Free(pubBuf);
|
||||
Free(priv);
|
||||
return "";
|
||||
let pair: String = String_Concat(pubB64, ":");
|
||||
return String_Concat(pair, privB64);
|
||||
}
|
||||
// Return "pub_b64:priv_b64"
|
||||
let pubB64: String = bux_base64_encode(pubBuf as String, ED25519_PUBKEY_SIZE);
|
||||
let privB64: String = bux_base64_encode(priv as String, ED25519_PRIVKEY_SIZE);
|
||||
Free(pubBuf);
|
||||
Free(priv);
|
||||
let pair: String = String_Concat(pubB64, ":");
|
||||
return String_Concat(pair, privB64);
|
||||
}
|
||||
|
||||
// --- Sign ---
|
||||
// --- Sign ---
|
||||
|
||||
// Ed25519_Sign: sign data with 32-byte raw private key. Returns 64-byte raw signature.
|
||||
func Ed25519_Sign(privKey: String, data: String) -> String {
|
||||
let sig: *void = Alloc(ED25519_SIG_SIZE as uint);
|
||||
if bux_ed25519_sign(privKey, data, String_Len(data) as int, sig) != 1 {
|
||||
Free(sig);
|
||||
return "";
|
||||
// Ed25519_Sign: sign data with 32-byte raw private key. Returns 64-byte raw signature.
|
||||
func Ed25519_Sign(privKey: String, data: String) -> String {
|
||||
let sig: *void = Alloc(ED25519_SIG_SIZE as uint);
|
||||
if bux_ed25519_sign(privKey, data, String_Len(data) as int, sig) != 1 {
|
||||
Free(sig);
|
||||
return "";
|
||||
}
|
||||
return sig as String;
|
||||
}
|
||||
return sig as String;
|
||||
}
|
||||
|
||||
// Convenience: sign and return base64-encoded signature
|
||||
func Ed25519_SignBase64(privKey: String, data: String) -> String {
|
||||
let sig: String = Ed25519_Sign(privKey, data);
|
||||
if String_Len(sig) == 0 { return ""; }
|
||||
return bux_base64_encode(sig, ED25519_SIG_SIZE);
|
||||
}
|
||||
// Convenience: sign and return base64-encoded signature
|
||||
func Ed25519_SignBase64(privKey: String, data: String) -> String {
|
||||
let sig: String = Ed25519_Sign(privKey, data);
|
||||
if String_Len(sig) == 0 { return ""; }
|
||||
return bux_base64_encode(sig, ED25519_SIG_SIZE);
|
||||
}
|
||||
|
||||
// --- Verify ---
|
||||
// --- Verify ---
|
||||
|
||||
// Ed25519_Verify: verify a 64-byte raw signature against data with 32-byte public key.
|
||||
func Ed25519_Verify(pubKey: String, signature: String, data: String) -> bool {
|
||||
let r: int = bux_ed25519_verify(pubKey, signature, data, String_Len(data) as int);
|
||||
return r == 1;
|
||||
}
|
||||
// Ed25519_Verify: verify a 64-byte raw signature against data with 32-byte public key.
|
||||
func Ed25519_Verify(pubKey: String, signature: String, data: String) -> bool {
|
||||
let r: int = bux_ed25519_verify(pubKey, signature, data, String_Len(data) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
// Convenience: verify a base64-encoded signature
|
||||
func Ed25519_VerifyBase64(pubKey: String, signatureB64: String, data: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
if outlen != ED25519_SIG_SIZE { return false; }
|
||||
return Ed25519_Verify(pubKey, sig, data);
|
||||
}
|
||||
// Convenience: verify a base64-encoded signature
|
||||
func Ed25519_VerifyBase64(pubKey: String, signatureB64: String, data: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
if outlen != ED25519_SIG_SIZE { return false; }
|
||||
return Ed25519_Verify(pubKey, sig, data);
|
||||
}
|
||||
}
|
||||
|
||||
+64
-64
@@ -3,71 +3,71 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Hash {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
extern func bux_sha1(data: String, len: int, out: *void);
|
||||
extern func bux_sha256(data: String, len: int, out: *void);
|
||||
extern func bux_sha384(data: String, len: int, out: *void);
|
||||
extern func bux_sha512(data: String, len: int, out: *void);
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
extern func bux_sha1(data: String, len: int, out: *void);
|
||||
extern func bux_sha256(data: String, len: int, out: *void);
|
||||
extern func bux_sha384(data: String, len: int, out: *void);
|
||||
extern func bux_sha512(data: String, len: int, out: *void);
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
|
||||
// --- Convenience wrappers: hex output ---
|
||||
// --- Convenience wrappers: hex output ---
|
||||
|
||||
func Hash_Sha1(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(20);
|
||||
bux_sha1(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 20);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha256(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_sha256(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha384(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_sha384(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha512(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_sha512(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Raw binary output (caller must Alloc/Free) ---
|
||||
|
||||
func Hash_Sha256Raw(data: String, out: *void) {
|
||||
bux_sha256(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
func Hash_Sha384Raw(data: String, out: *void) {
|
||||
bux_sha384(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
func Hash_Sha512Raw(data: String, out: *void) {
|
||||
bux_sha512(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
// --- Digest sizes ---
|
||||
|
||||
func Hash_Sha1Size() -> int { return 20; }
|
||||
func Hash_Sha256Size() -> int { return 32; }
|
||||
func Hash_Sha384Size() -> int { return 48; }
|
||||
func Hash_Sha512Size() -> int { return 64; }
|
||||
func Hash_Sha1(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(20);
|
||||
bux_sha1(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 20);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha256(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_sha256(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha384(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_sha384(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hash_Sha512(data: String) -> String {
|
||||
let len: int = String_Len(data) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_sha512(data, len, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Raw binary output (caller must Alloc/Free) ---
|
||||
|
||||
func Hash_Sha256Raw(data: String, out: *void) {
|
||||
bux_sha256(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
func Hash_Sha384Raw(data: String, out: *void) {
|
||||
bux_sha384(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
func Hash_Sha512Raw(data: String, out: *void) {
|
||||
bux_sha512(data, String_Len(data) as int, out);
|
||||
}
|
||||
|
||||
// --- Digest sizes ---
|
||||
|
||||
func Hash_Sha1Size() -> int { return 20; }
|
||||
func Hash_Sha256Size() -> int { return 32; }
|
||||
func Hash_Sha384Size() -> int { return 48; }
|
||||
func Hash_Sha512Size() -> int { return 64; }
|
||||
}
|
||||
|
||||
+83
-83
@@ -3,90 +3,90 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Hmac {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
extern func bux_hmac_sha256(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_hmac_sha384(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_hmac_sha512(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_hmac_sha256(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_hmac_sha384(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_hmac_sha512(key: String, keylen: int, msg: String, msglen: int, out: *void);
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
|
||||
// --- HMAC-SHA256 ---
|
||||
// --- HMAC-SHA256 ---
|
||||
|
||||
func Hmac_Sha256(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha256Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha256(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha256Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- HMAC-SHA384 ---
|
||||
|
||||
func Hmac_Sha384(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_hmac_sha384(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha384Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha384(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha384Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_hmac_sha384(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- HMAC-SHA512 ---
|
||||
|
||||
func Hmac_Sha512(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_hmac_sha512(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha512Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha512(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha512Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_hmac_sha512(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
func Hmac_Sha256(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha256Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha256(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha256Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(32);
|
||||
bux_hmac_sha256(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- HMAC-SHA384 ---
|
||||
|
||||
func Hmac_Sha384(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_hmac_sha384(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha384Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha384(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha384Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(48);
|
||||
bux_hmac_sha384(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- HMAC-SHA512 ---
|
||||
|
||||
func Hmac_Sha512(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_hmac_sha512(key, kl, message, ml, buf);
|
||||
let result: String = bux_bytes_to_hex(buf, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Hmac_Sha512Raw(key: String, message: String, out: *void) {
|
||||
bux_hmac_sha512(key, String_Len(key) as int, message, String_Len(message) as int, out);
|
||||
}
|
||||
|
||||
func Hmac_Sha512Base64(key: String, message: String) -> String {
|
||||
let kl: int = String_Len(key) as int;
|
||||
let ml: int = String_Len(message) as int;
|
||||
let buf: *void = Alloc(64);
|
||||
bux_hmac_sha512(key, kl, message, ml, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+206
-206
@@ -4,233 +4,233 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Jwt {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len, String_Eq, String_StartsWith, String_Concat};
|
||||
import Std::Crypto::Base64::{Base64URL_Encode, Base64URL_Decode};
|
||||
import Std::Crypto::Hash::{Hash_Sha256Raw, Hash_Sha384Raw, Hash_Sha512Raw};
|
||||
import Std::Crypto::Hmac::{Hmac_Sha256Raw, Hmac_Sha384Raw, Hmac_Sha512Raw};
|
||||
import Std::Crypto::Rsa::{Rsa_SignSha256, Rsa_SignSha384, Rsa_SignSha512,
|
||||
Rsa_VerifySha256, Rsa_VerifySha384, Rsa_VerifySha512};
|
||||
import Std::Crypto::Ecdsa::{Ecdsa_SignP256, Ecdsa_SignP384, Ecdsa_VerifyP256, Ecdsa_VerifyP384};
|
||||
import Std::Crypto::Ed25519::{Ed25519_Sign, Ed25519_Verify};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len, String_Eq, String_StartsWith, String_Concat};
|
||||
import Std::Crypto::Base64::{Base64URL_Encode, Base64URL_Decode};
|
||||
import Std::Crypto::Hash::{Hash_Sha256Raw, Hash_Sha384Raw, Hash_Sha512Raw};
|
||||
import Std::Crypto::Hmac::{Hmac_Sha256Raw, Hmac_Sha384Raw, Hmac_Sha512Raw};
|
||||
import Std::Crypto::Rsa::{Rsa_SignSha256, Rsa_SignSha384, Rsa_SignSha512,
|
||||
Rsa_VerifySha256, Rsa_VerifySha384, Rsa_VerifySha512};
|
||||
import Std::Crypto::Ecdsa::{Ecdsa_SignP256, Ecdsa_SignP384, Ecdsa_VerifyP256, Ecdsa_VerifyP384};
|
||||
import Std::Crypto::Ed25519::{Ed25519_Sign, Ed25519_Verify};
|
||||
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_str_split_count(s: String, delim: String) -> uint;
|
||||
extern func bux_str_split_part(s: String, delim: String, index: uint) -> String;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_str_split_count(s: String, delim: String) -> uint;
|
||||
extern func bux_str_split_part(s: String, delim: String, index: uint) -> String;
|
||||
|
||||
// --- JWT Algorithm enum ---
|
||||
enum JwtAlg {
|
||||
HS256,
|
||||
HS384,
|
||||
HS512,
|
||||
RS256,
|
||||
RS384,
|
||||
RS512,
|
||||
ES256,
|
||||
ES384,
|
||||
EdDSA,
|
||||
}
|
||||
|
||||
// --- Header ---
|
||||
|
||||
// Jwt_MakeHeader: build the JWT header JSON string for the given algorithm
|
||||
func Jwt_MakeHeader(alg: JwtAlg) -> String {
|
||||
if alg.tag == JwtAlg_HS256 { return "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_HS384 { return "{\"alg\":\"HS384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_HS512 { return "{\"alg\":\"HS512\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS256 { return "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS384 { return "{\"alg\":\"RS384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS512 { return "{\"alg\":\"RS512\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_ES256 { return "{\"alg\":\"ES256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_ES384 { return "{\"alg\":\"ES384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_EdDSA { return "{\"alg\":\"EdDSA\",\"typ\":\"JWT\"}"; }
|
||||
return "{\"alg\":\"none\",\"typ\":\"JWT\"}";
|
||||
}
|
||||
|
||||
// --- Signing ---
|
||||
|
||||
// Sign the JWT signing input with the given algorithm
|
||||
func Jwt_Sign(alg: JwtAlg, signingInput: String, key: String) -> String {
|
||||
// --- HMAC algorithms ---
|
||||
if alg.tag == JwtAlg_HS256 {
|
||||
let buf: *void = Alloc(32);
|
||||
Hmac_Sha256Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
if alg.tag == JwtAlg_HS384 {
|
||||
let buf: *void = Alloc(48);
|
||||
Hmac_Sha384Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
if alg.tag == JwtAlg_HS512 {
|
||||
let buf: *void = Alloc(64);
|
||||
Hmac_Sha512Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
// --- JWT Algorithm enum ---
|
||||
enum JwtAlg {
|
||||
HS256,
|
||||
HS384,
|
||||
HS512,
|
||||
RS256,
|
||||
RS384,
|
||||
RS512,
|
||||
ES256,
|
||||
ES384,
|
||||
EdDSA,
|
||||
}
|
||||
|
||||
// --- RSA algorithms (key is PEM private key) ---
|
||||
if alg.tag == JwtAlg_RS256 {
|
||||
let raw: String = Rsa_SignSha256(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_RS384 {
|
||||
let raw: String = Rsa_SignSha384(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_RS512 {
|
||||
let raw: String = Rsa_SignSha512(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
// --- Header ---
|
||||
|
||||
// Jwt_MakeHeader: build the JWT header JSON string for the given algorithm
|
||||
func Jwt_MakeHeader(alg: JwtAlg) -> String {
|
||||
if alg.tag == JwtAlg_HS256 { return "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_HS384 { return "{\"alg\":\"HS384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_HS512 { return "{\"alg\":\"HS512\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS256 { return "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS384 { return "{\"alg\":\"RS384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_RS512 { return "{\"alg\":\"RS512\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_ES256 { return "{\"alg\":\"ES256\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_ES384 { return "{\"alg\":\"ES384\",\"typ\":\"JWT\"}"; }
|
||||
if alg.tag == JwtAlg_EdDSA { return "{\"alg\":\"EdDSA\",\"typ\":\"JWT\"}"; }
|
||||
return "{\"alg\":\"none\",\"typ\":\"JWT\"}";
|
||||
}
|
||||
|
||||
// --- ECDSA algorithms (key is PEM private key) ---
|
||||
if alg.tag == JwtAlg_ES256 {
|
||||
let raw: String = Ecdsa_SignP256(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_ES384 {
|
||||
let raw: String = Ecdsa_SignP384(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
// --- Signing ---
|
||||
|
||||
// Sign the JWT signing input with the given algorithm
|
||||
func Jwt_Sign(alg: JwtAlg, signingInput: String, key: String) -> String {
|
||||
// --- HMAC algorithms ---
|
||||
if alg.tag == JwtAlg_HS256 {
|
||||
let buf: *void = Alloc(32);
|
||||
Hmac_Sha256Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 32);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
if alg.tag == JwtAlg_HS384 {
|
||||
let buf: *void = Alloc(48);
|
||||
Hmac_Sha384Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 48);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
if alg.tag == JwtAlg_HS512 {
|
||||
let buf: *void = Alloc(64);
|
||||
Hmac_Sha512Raw(key, signingInput, buf);
|
||||
let result: String = bux_base64_encode(buf as String, 64);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- RSA algorithms (key is PEM private key) ---
|
||||
if alg.tag == JwtAlg_RS256 {
|
||||
let raw: String = Rsa_SignSha256(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_RS384 {
|
||||
let raw: String = Rsa_SignSha384(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_RS512 {
|
||||
let raw: String = Rsa_SignSha512(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
// --- ECDSA algorithms (key is PEM private key) ---
|
||||
if alg.tag == JwtAlg_ES256 {
|
||||
let raw: String = Ecdsa_SignP256(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
if alg.tag == JwtAlg_ES384 {
|
||||
let raw: String = Ecdsa_SignP384(key, signingInput);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
// --- EdDSA (key is 32-byte raw private key) ---
|
||||
if alg.tag == JwtAlg_EdDSA {
|
||||
return Ed25519_Sign(key, signingInput);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// --- EdDSA (key is 32-byte raw private key) ---
|
||||
if alg.tag == JwtAlg_EdDSA {
|
||||
return Ed25519_Sign(key, signingInput);
|
||||
}
|
||||
// --- Verify ---
|
||||
|
||||
return "";
|
||||
}
|
||||
// Verify a JWT signature
|
||||
func Jwt_Verify(alg: JwtAlg, signingInput: String, signatureB64: String, key: String) -> bool {
|
||||
// --- HMAC algorithms ---
|
||||
if alg.tag == JwtAlg_HS256 {
|
||||
let expectBuf: *void = Alloc(32);
|
||||
Hmac_Sha256Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 32);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
if alg.tag == JwtAlg_HS384 {
|
||||
let expectBuf: *void = Alloc(48);
|
||||
Hmac_Sha384Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 48);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
if alg.tag == JwtAlg_HS512 {
|
||||
let expectBuf: *void = Alloc(64);
|
||||
Hmac_Sha512Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 64);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
|
||||
// --- Verify ---
|
||||
// --- RSA algorithms ---
|
||||
if alg.tag == JwtAlg_RS256 { return Rsa_VerifySha256(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_RS384 { return Rsa_VerifySha384(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_RS512 { return Rsa_VerifySha512(key, signingInput, signatureB64); }
|
||||
|
||||
// Verify a JWT signature
|
||||
func Jwt_Verify(alg: JwtAlg, signingInput: String, signatureB64: String, key: String) -> bool {
|
||||
// --- HMAC algorithms ---
|
||||
if alg.tag == JwtAlg_HS256 {
|
||||
let expectBuf: *void = Alloc(32);
|
||||
Hmac_Sha256Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 32);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
if alg.tag == JwtAlg_HS384 {
|
||||
let expectBuf: *void = Alloc(48);
|
||||
Hmac_Sha384Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 48);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
if alg.tag == JwtAlg_HS512 {
|
||||
let expectBuf: *void = Alloc(64);
|
||||
Hmac_Sha512Raw(key, signingInput, expectBuf);
|
||||
let expectB64: String = bux_base64_encode(expectBuf as String, 64);
|
||||
Free(expectBuf);
|
||||
return String_Eq(expectB64, signatureB64);
|
||||
}
|
||||
// --- ECDSA algorithms ---
|
||||
if alg.tag == JwtAlg_ES256 { return Ecdsa_VerifyP256(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_ES384 { return Ecdsa_VerifyP384(key, signingInput, signatureB64); }
|
||||
|
||||
// --- RSA algorithms ---
|
||||
if alg.tag == JwtAlg_RS256 { return Rsa_VerifySha256(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_RS384 { return Rsa_VerifySha384(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_RS512 { return Rsa_VerifySha512(key, signingInput, signatureB64); }
|
||||
// --- EdDSA ---
|
||||
if alg.tag == JwtAlg_EdDSA { return Ed25519_Verify(key, signatureB64, signingInput); }
|
||||
|
||||
// --- ECDSA algorithms ---
|
||||
if alg.tag == JwtAlg_ES256 { return Ecdsa_VerifyP256(key, signingInput, signatureB64); }
|
||||
if alg.tag == JwtAlg_ES384 { return Ecdsa_VerifyP384(key, signingInput, signatureB64); }
|
||||
|
||||
// --- EdDSA ---
|
||||
if alg.tag == JwtAlg_EdDSA { return Ed25519_Verify(key, signatureB64, signingInput); }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Encode ---
|
||||
|
||||
// Jwt_Encode: create a signed JWT
|
||||
// headerJson — JSON header string (use Jwt_MakeHeader or custom)
|
||||
// payloadJson — JSON payload/claims string
|
||||
// alg — signing algorithm
|
||||
// key — signing key (HMAC secret, RSA PEM, ECDSA PEM, or Ed25519 raw privkey)
|
||||
// Returns the complete "header.payload.signature" JWT string
|
||||
func Jwt_Encode(headerJson: String, payloadJson: String, alg: JwtAlg, key: String) -> String {
|
||||
let headerB64: String = Base64URL_Encode(headerJson);
|
||||
let payloadB64: String = Base64URL_Encode(payloadJson);
|
||||
let signingInput: String = String_Concat(headerB64, ".");
|
||||
let signingInputFull: String = String_Concat(signingInput, payloadB64);
|
||||
|
||||
let sigB64: String = Jwt_Sign(alg, signingInputFull, key);
|
||||
|
||||
let part1: String = String_Concat(signingInputFull, ".");
|
||||
return String_Concat(part1, sigB64);
|
||||
}
|
||||
|
||||
// --- Decode ---
|
||||
|
||||
// Jwt_Decode: decode and verify a JWT.
|
||||
// token — the full "header.payload.signature" string
|
||||
// alg — expected algorithm
|
||||
// key — verification key
|
||||
// headerOut — receives decoded header JSON
|
||||
// payloadOut — receives decoded payload JSON
|
||||
// Returns true if signature is valid.
|
||||
func Jwt_Decode(token: String, alg: JwtAlg, key: String,
|
||||
headerOut: *String, payloadOut: *String) -> bool {
|
||||
// Split by "."
|
||||
let partCount: uint = bux_str_split_count(token, ".");
|
||||
if partCount != 3 { return false; }
|
||||
|
||||
let headerB64: String = bux_str_split_part(token, ".", 0);
|
||||
let payloadB64: String = bux_str_split_part(token, ".", 1);
|
||||
let sigB64: String = bux_str_split_part(token, ".", 2);
|
||||
|
||||
// Build signing input
|
||||
let input: String = String_Concat(headerB64, ".");
|
||||
let signingInput: String = String_Concat(input, payloadB64);
|
||||
|
||||
// Verify signature
|
||||
if !Jwt_Verify(alg, signingInput, sigB64, key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode
|
||||
headerOut[0] = Base64URL_Decode(headerB64);
|
||||
payloadOut[0] = Base64URL_Decode(payloadB64);
|
||||
return true;
|
||||
}
|
||||
// --- Encode ---
|
||||
|
||||
// --- Convenience: Encode with standard header ---
|
||||
// Jwt_Encode: create a signed JWT
|
||||
// headerJson — JSON header string (use Jwt_MakeHeader or custom)
|
||||
// payloadJson — JSON payload/claims string
|
||||
// alg — signing algorithm
|
||||
// key — signing key (HMAC secret, RSA PEM, ECDSA PEM, or Ed25519 raw privkey)
|
||||
// Returns the complete "header.payload.signature" JWT string
|
||||
func Jwt_Encode(headerJson: String, payloadJson: String, alg: JwtAlg, key: String) -> String {
|
||||
let headerB64: String = Base64URL_Encode(headerJson);
|
||||
let payloadB64: String = Base64URL_Encode(payloadJson);
|
||||
let signingInput: String = String_Concat(headerB64, ".");
|
||||
let signingInputFull: String = String_Concat(signingInput, payloadB64);
|
||||
|
||||
func Jwt_EncodeHS256(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS256 }, secret);
|
||||
}
|
||||
let sigB64: String = Jwt_Sign(alg, signingInputFull, key);
|
||||
|
||||
func Jwt_EncodeHS384(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS384 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS384 }, secret);
|
||||
}
|
||||
let part1: String = String_Concat(signingInputFull, ".");
|
||||
return String_Concat(part1, sigB64);
|
||||
}
|
||||
|
||||
func Jwt_EncodeHS512(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS512 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS512 }, secret);
|
||||
}
|
||||
// --- Decode ---
|
||||
|
||||
func Jwt_EncodeRS256(payloadJson: String, pemPrivateKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_RS256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_RS256 }, pemPrivateKey);
|
||||
}
|
||||
// Jwt_Decode: decode and verify a JWT.
|
||||
// token — the full "header.payload.signature" string
|
||||
// alg — expected algorithm
|
||||
// key — verification key
|
||||
// headerOut — receives decoded header JSON
|
||||
// payloadOut — receives decoded payload JSON
|
||||
// Returns true if signature is valid.
|
||||
func Jwt_Decode(token: String, alg: JwtAlg, key: String,
|
||||
headerOut: *String, payloadOut: *String) -> bool {
|
||||
// Split by "."
|
||||
let partCount: uint = bux_str_split_count(token, ".");
|
||||
if partCount != 3 { return false; }
|
||||
|
||||
func Jwt_EncodeES256(payloadJson: String, pemPrivateKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_ES256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_ES256 }, pemPrivateKey);
|
||||
}
|
||||
let headerB64: String = bux_str_split_part(token, ".", 0);
|
||||
let payloadB64: String = bux_str_split_part(token, ".", 1);
|
||||
let sigB64: String = bux_str_split_part(token, ".", 2);
|
||||
|
||||
func Jwt_EncodeEdDSA(payloadJson: String, rawPrivKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_EdDSA });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_EdDSA }, rawPrivKey);
|
||||
}
|
||||
// Build signing input
|
||||
let input: String = String_Concat(headerB64, ".");
|
||||
let signingInput: String = String_Concat(input, payloadB64);
|
||||
|
||||
// Verify signature
|
||||
if !Jwt_Verify(alg, signingInput, sigB64, key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode
|
||||
headerOut[0] = Base64URL_Decode(headerB64);
|
||||
payloadOut[0] = Base64URL_Decode(payloadB64);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Convenience: Encode with standard header ---
|
||||
|
||||
func Jwt_EncodeHS256(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS256 }, secret);
|
||||
}
|
||||
|
||||
func Jwt_EncodeHS384(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS384 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS384 }, secret);
|
||||
}
|
||||
|
||||
func Jwt_EncodeHS512(payloadJson: String, secret: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_HS512 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_HS512 }, secret);
|
||||
}
|
||||
|
||||
func Jwt_EncodeRS256(payloadJson: String, pemPrivateKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_RS256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_RS256 }, pemPrivateKey);
|
||||
}
|
||||
|
||||
func Jwt_EncodeES256(payloadJson: String, pemPrivateKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_ES256 });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_ES256 }, pemPrivateKey);
|
||||
}
|
||||
|
||||
func Jwt_EncodeEdDSA(payloadJson: String, rawPrivKey: String) -> String {
|
||||
let header: String = Jwt_MakeHeader(JwtAlg { tag: JwtAlg_EdDSA });
|
||||
return Jwt_Encode(header, payloadJson, JwtAlg { tag: JwtAlg_EdDSA }, rawPrivKey);
|
||||
}
|
||||
}
|
||||
|
||||
+45
-45
@@ -3,61 +3,61 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Random {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
extern func bux_random_bytes(buf: *void, len: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
|
||||
|
||||
// RandomBytes: returns n cryptographically secure random bytes as a raw string
|
||||
func Random_Bytes(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
// RandomBytes: returns n cryptographically secure random bytes as a raw string
|
||||
func Random_Bytes(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
// Return raw buffer as string (binary-safe)
|
||||
return buf as String;
|
||||
}
|
||||
// Return raw buffer as string (binary-safe)
|
||||
return buf as String;
|
||||
}
|
||||
|
||||
// RandomHex: returns n random bytes as lowercase hex
|
||||
func Random_Hex(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
// RandomHex: returns n random bytes as lowercase hex
|
||||
func Random_Hex(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
let result: String = bux_bytes_to_hex(buf, n);
|
||||
Free(buf);
|
||||
return "";
|
||||
return result;
|
||||
}
|
||||
let result: String = bux_bytes_to_hex(buf, n);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// RandomBase64: returns n random bytes as base64-encoded string
|
||||
func Random_Base64(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
// RandomBase64: returns n random bytes as base64-encoded string
|
||||
func Random_Base64(n: int) -> String {
|
||||
if n <= 0 { return ""; }
|
||||
let buf: *void = Alloc(n as uint);
|
||||
if bux_random_bytes(buf, n) != 1 {
|
||||
Free(buf);
|
||||
return "";
|
||||
}
|
||||
let result: String = bux_base64_encode(buf as String, n);
|
||||
Free(buf);
|
||||
return "";
|
||||
return result;
|
||||
}
|
||||
let result: String = bux_base64_encode(buf as String, n);
|
||||
Free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
// RandomUint32: returns a random 32-bit unsigned integer
|
||||
func Random_Uint32() -> uint {
|
||||
let buf: *void = Alloc(4);
|
||||
if bux_random_bytes(buf, 4) != 1 {
|
||||
// RandomUint32: returns a random 32-bit unsigned integer
|
||||
func Random_Uint32() -> uint {
|
||||
let buf: *void = Alloc(4);
|
||||
if bux_random_bytes(buf, 4) != 1 {
|
||||
Free(buf);
|
||||
return 0;
|
||||
}
|
||||
// Interpret first 4 bytes as uint (native endian)
|
||||
let ptr: *uint = buf as *uint;
|
||||
let val: uint = *ptr;
|
||||
Free(buf);
|
||||
return 0;
|
||||
return val;
|
||||
}
|
||||
// Interpret first 4 bytes as uint (native endian)
|
||||
let ptr: *uint = buf as *uint;
|
||||
let val: uint = *ptr;
|
||||
Free(buf);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
+81
-81
@@ -3,88 +3,88 @@
|
||||
// =============================================================================
|
||||
module Std::Crypto::Rsa {
|
||||
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
import Std::Mem::{Alloc, Free};
|
||||
import Std::String::{String_Len};
|
||||
|
||||
// Extern declarations for the runtime C implementations
|
||||
extern func bux_rsa_sign_sha256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_sign_sha384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_sign_sha512(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_verify_sha256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_rsa_verify_sha384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_rsa_verify_sha512(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
// Extern declarations for the runtime C implementations
|
||||
extern func bux_rsa_sign_sha256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_sign_sha384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_sign_sha512(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String;
|
||||
extern func bux_rsa_verify_sha256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_rsa_verify_sha384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_rsa_verify_sha512(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int;
|
||||
extern func bux_base64_encode(data: String, len: int) -> String;
|
||||
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
|
||||
|
||||
// --- RSA Sign ---
|
||||
// --- RSA Sign ---
|
||||
|
||||
// Rsa_SignSha256: sign data with RSA private key (PEM format), returns raw signature
|
||||
func Rsa_SignSha256(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Rsa_SignSha384(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Rsa_SignSha512(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha512(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
// Convenience: sign and return base64-encoded signature
|
||||
func Rsa_SignSha256Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha256(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Rsa_SignSha384Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha384(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Rsa_SignSha512Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha512(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
// --- RSA Verify ---
|
||||
|
||||
// Rsa_VerifySha256: verify raw signature against data with RSA public key (PEM)
|
||||
// Returns true if signature is valid.
|
||||
func Rsa_VerifySha256(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Rsa_VerifySha384(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Rsa_VerifySha512(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha512(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
// Convenience: verify base64-encoded signature
|
||||
func Rsa_VerifySha256Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha256(pemPublicKey, data, sig);
|
||||
}
|
||||
|
||||
func Rsa_VerifySha384Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha384(pemPublicKey, data, sig);
|
||||
}
|
||||
|
||||
func Rsa_VerifySha512Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha512(pemPublicKey, data, sig);
|
||||
}
|
||||
// Rsa_SignSha256: sign data with RSA private key (PEM format), returns raw signature
|
||||
func Rsa_SignSha256(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Rsa_SignSha384(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
func Rsa_SignSha512(pemPrivateKey: String, data: String) -> String {
|
||||
let siglen: int = 0;
|
||||
return bux_rsa_sign_sha512(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen);
|
||||
}
|
||||
|
||||
// Convenience: sign and return base64-encoded signature
|
||||
func Rsa_SignSha256Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha256(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Rsa_SignSha384Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha384(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
func Rsa_SignSha512Base64(pemPrivateKey: String, data: String) -> String {
|
||||
let raw: String = Rsa_SignSha512(pemPrivateKey, data);
|
||||
return bux_base64_encode(raw, String_Len(raw) as int);
|
||||
}
|
||||
|
||||
// --- RSA Verify ---
|
||||
|
||||
// Rsa_VerifySha256: verify raw signature against data with RSA public key (PEM)
|
||||
// Returns true if signature is valid.
|
||||
func Rsa_VerifySha256(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Rsa_VerifySha384(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
func Rsa_VerifySha512(pemPublicKey: String, data: String, signature: String) -> bool {
|
||||
let r: int = bux_rsa_verify_sha512(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int);
|
||||
return r == 1;
|
||||
}
|
||||
|
||||
// Convenience: verify base64-encoded signature
|
||||
func Rsa_VerifySha256Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha256(pemPublicKey, data, sig);
|
||||
}
|
||||
|
||||
func Rsa_VerifySha384Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha384(pemPublicKey, data, sig);
|
||||
}
|
||||
|
||||
func Rsa_VerifySha512Base64(pemPublicKey: String, data: String, signatureB64: String) -> bool {
|
||||
let outlen: int = 0;
|
||||
let sig: String = bux_base64_decode(signatureB64, String_Len(signatureB64) as int, &outlen);
|
||||
return Rsa_VerifySha512(pemPublicKey, data, sig);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user