Local typed actors with bounded mailboxes for the Moon-Lander framework
| Package | Alias | Targets | Contents |
|---|---|---|---|
| moonrockz/moon-lander-actors | @policy | wasm, wasm-gc, js, native | Checked policy values: MailboxCapacity, MessageCount, MailboxPolicy, Admission, PayloadPolicy |
| moonrockz/moon-lander-actors/runtime | @actors | wasm, js, native | Scopes, actors, references, replies and Receive values. See the runtime guide |
graph LR
core[moon-lander-core] --> policy["actors (policy, portable)"]
ion["Ion data model"] --> policy
policy --> runtime["actors/runtime"]
async[moonbitlang/async] --> runtime///|
test "a capacity is positive" {
assert_eq(@policy.MailboxCapacity::from_int(1).to_int(), 1)
let rejected = try {
ignore(@policy.MailboxCapacity::from_int(0))
None
} catch {
InvalidCapacity(input~, rule=NotPositive) => Some(input)
InvalidCount(..) => None
}
assert_eq(rejected, Some(0))
}///|
test "the default policy is bounded at 128" {
guard @policy.MailboxPolicy::default() is Bounded(capacity) else {
fail("the default is unbounded")
}
assert_eq(capacity.to_int(), 128)
assert_true(@policy.MailboxPolicy::Unbounded != @policy.MailboxPolicy::default())
}///|
enum Change {
Add(Int)
} derive(ToJson)
///|
test "omit is the default and JSON bridges a derived protocol" {
let omitted : @policy.PayloadPolicy[Change] = @policy.PayloadPolicy::default()
assert_true(omitted.apply(Add(3)) is None)
assert_true(@policy.PayloadPolicy::omit().apply(Add(3)) is None)
let json : @policy.PayloadPolicy[Change] = @policy.PayloadPolicy::json()
guard json.apply(Add(3)) is Some(payload) else { fail("missing payload") }
assert_true(payload.equals(@ion.Ion(ToJson::to_json(Add(3)))))
}///|
enum Measurement {
Record(@ion.Decimal, @ion.Timestamp)
}
///|
impl @ion.ToIon for Measurement with to_ion(self) {
let Record(amount, time) = self
@ion.Ion::list([@ion.Ion::decimal(amount), @ion.Ion::timestamp(time)])
}
///|
test "Ion keeps decimal and timestamp types" {
let amount = @ion.Decimal::parse("12.340")
let time = @ion.Timestamp::parse("2026-10-31T12:34:56Z")
let policy : @policy.PayloadPolicy[Measurement] = @policy.PayloadPolicy::ion()
guard policy.apply(Record(amount, time)) is Some(payload) else { fail("missing payload") }
assert_true(payload.equals(@ion.Ion::list([
@ion.Ion::decimal(amount), @ion.Ion::timestamp(time),
])))
}///|
enum Login {
Authenticate(String, String)
}
///|
test "redact a secret before it enters an event" {
let policy : @policy.PayloadPolicy[Login] = @policy.PayloadPolicy::encode(message => {
let Authenticate(user, _secret) = message
@ion.Ion::from_fields([
@ion.Field("user", @ion.Ion::string(user)),
@ion.Field("secret", @ion.Ion::string("[redacted]")),
])
})
guard policy.apply(Authenticate("reader", "private-token")) is Some(payload) else {
fail("missing payload")
}
assert_true(payload.equals(@ion.Ion::from_fields([
@ion.Field("user", @ion.Ion::string("reader")),
@ion.Field("secret", @ion.Ion::string("[redacted]")),
])))
}pub struct PayloadPolicy[M] {
// private fields
}