///|
pub(all) struct StorePutRequest[T] {
item : T
callback : () -> Unit
}
///|
pub(all) struct StoreGetRequest[T] {
callback : (T) -> Unit
}
///|
pub(all) struct Store[T] {
name : String
capacity : Int
priv items : Array[T]
priv put_queue : Array[StorePutRequest[T]]
priv get_queue : Array[StoreGetRequest[T]]
}
///|
pub fn[T] Store::new(name : String, capacity : Int) -> Store[T] {
if capacity <= 0 {
abort("Store capacity must be positive")
}
{ name, capacity, items: [], put_queue: [], get_queue: [] }
}
///|
pub fn[T] Store::size(self : Store[T]) -> Int {
self.items.length()
}
///|
pub fn[T] Store::capacity(self : Store[T]) -> Int {
self.capacity
}
///|
pub fn[T] Store::put(self : Store[T], item : T, callback : () -> Unit) -> Unit {
if !self.get_queue.is_empty() {
let req = self.get_queue[0]
let _ = self.get_queue.remove(0)
callback()
(req.callback)(item)
} else if self.items.length() < self.capacity {
self.items.push(item)
callback()
} else {
self.put_queue.push({ item, callback })
}
}
///|
pub fn[T] Store::get(self : Store[T], callback : (T) -> Unit) -> Unit {
if !self.items.is_empty() {
let item = self.items[0]
let _ = self.items.remove(0)
callback(item)
if !self.put_queue.is_empty() {
let put_req = self.put_queue[0]
let _ = self.put_queue.remove(0)
self.items.push(put_req.item)
(put_req.callback)()
}
} else {
self.get_queue.push({ callback, })
}
}
///|
pub(all) struct Container {
name : String
capacity : Double
mut level : Double
priv get_queue : Array[(Double, (Bool) -> Unit)]
priv put_queue : Array[(Double, (Bool) -> Unit)]
}
///|
pub fn Container::new(
name : String,
capacity : Double,
initial_level : Double,
) -> Container {
if capacity <= 0.0 || initial_level < 0.0 || initial_level > capacity {
abort("Invalid Container initial parameters")
}
{ name, capacity, level: initial_level, get_queue: [], put_queue: [] }
}
///|
pub fn Container::level(self : Container) -> Double {
self.level
}
///|
pub fn Container::capacity(self : Container) -> Double {
self.capacity
}
///|
pub fn Container::put(
self : Container,
amount : Double,
callback : (Bool) -> Unit,
) -> Unit {
if amount <= 0.0 {
abort("Container put amount must be positive")
}
if self.level + amount <= self.capacity {
self.level = self.level + amount
callback(true)
self.process_get_queue()
} else {
self.put_queue.push((amount, callback))
}
}
///|
pub fn Container::get(
self : Container,
amount : Double,
callback : (Bool) -> Unit,
) -> Unit {
if amount <= 0.0 {
abort("Container get amount must be positive")
}
if self.level >= amount {
self.level = self.level - amount
callback(true)
self.process_put_queue()
} else {
self.get_queue.push((amount, callback))
}
}
///|
fn Container::process_get_queue(self : Container) -> Unit {
while !self.get_queue.is_empty() {
let (req_amt, cb) = self.get_queue[0]
if self.level >= req_amt {
self.level = self.level - req_amt
let _ = self.get_queue.remove(0)
cb(true)
self.process_put_queue()
} else {
break
}
}
}
///|
fn Container::process_put_queue(self : Container) -> Unit {
while !self.put_queue.is_empty() {
let (req_amt, cb) = self.put_queue[0]
if self.level + req_amt <= self.capacity {
self.level = self.level + req_amt
let _ = self.put_queue.remove(0)
cb(true)
self.process_get_queue()
} else {
break
}
}
}