package actors import "../uuid" Anything :: struct { data: any, ptr: rawptr, } new_anything :: proc(value: $T) -> Anything { p := new(T) p^ = value return Anything{p^, p} } free_anything :: proc(any: Anything) { free(any.ptr) } Any :: union { // booleans bool, b8, b16, b32, b64, // integers int, i8, i16, i32, i64, i128, uint, u8, u16, u32, u64, u128, uintptr, // endian specific integers // little endian i16le, i32le, i64le, i128le, u16le, u32le, u64le, u128le, // big endian i16be, i32be, i64be, i128be, u16be, u32be, u64be, u128be, // floating point numbers f16, f32, f64, // endian specific floating point numbers // little endian f16le, f32le, f64le, // big endian f16be, f32be, f64be, // complex numbers complex32, complex64, complex128, // quaternion numbers quaternion64, quaternion128, quaternion256, // signed 32 bit integer // represents a Unicode code point // is a distinct type to `i32` rune, // strings string, cstring, // raw pointer type rawptr, // runtime type information specific type typeid, // custom types ActorRef, // containers [dynamic]Any, map[string]Any, } State :: Any Behavior :: proc(self: ^Actor, sys: ^System, state: ^State, from: ActorRef, msg: any) Actor :: struct { ref: ActorRef, behavior: Behavior, last_behavior: Maybe(Behavior), state: State, } ActorRef :: struct { addr: string, } Message :: struct { to: ActorRef, from: ActorRef, msg: Anything, } System :: struct { actors: map[string]Actor, queue: [dynamic]Message, running: bool, } new_system :: proc() -> ^System { sys := new(System) sys.running = true sys.actors = make(map[string]Actor) sys.queue = make([dynamic]Message, 0) return sys } destroy_system :: proc(sys: ^System) { for len(sys.queue) > 0 { msg := pop(&sys.queue) free_anything(msg.msg) } delete(sys.queue) delete(sys.actors) free(sys) } spawn :: proc(sys: ^System, state: State, behavior: Behavior) -> ActorRef { id := uuid.generate() id_string, err := uuid.clone_to_string(id) assert(err == nil) ref := ActorRef{id_string} sys.actors[id_string] = Actor{ref, behavior, nil, state} return ref } become :: proc(self: ^Actor, behavior: Behavior) { self^.last_behavior = self^.behavior self^.behavior = behavior } unbecome :: proc(self: ^Actor) { if self^.last_behavior != nil { self^.behavior = self^.last_behavior.? } } send :: proc(sys: ^System, from: ActorRef, to: ActorRef, msg: $T) { m := new_anything(msg) append(&sys.queue, Message{to, from, m}) } stop :: proc(sys: ^System) { sys.running = false } work :: proc(sys: ^System) { for sys.running { if len(sys.queue) == 0 { break } msg := pop_front(&sys.queue) actor := &sys.actors[msg.to.addr] actor.behavior(actor, sys, &actor.state, msg.from, msg.msg.data) free_anything(msg.msg) } }