///|
pub(all) struct ResourceRequest {
id : Int
amount : Int
priority : Int
callback : (Bool) -> Unit
mut cancelled : Bool
}
///|
pub(all) struct Resource {
name : String
capacity : Int
mut available : Int
priv wait_queue : Array[ResourceRequest]
mut next_req_id : Int
}
///|
pub fn Resource::new(name : String, capacity : Int) -> Resource {
if capacity <= 0 {
abort("Resource capacity must be positive")
}
{ name, capacity, available: capacity, wait_queue: [], next_req_id: 1 }
}
///|
pub fn Resource::available(self : Resource) -> Int {
self.available
}
///|
pub fn Resource::capacity(self : Resource) -> Int {
self.capacity
}
///|
pub fn Resource::queue_length(self : Resource) -> Int {
let mut count = 0
for req in self.wait_queue {
if !req.cancelled {
count = count + 1
}
}
count
}
///|
pub fn Resource::request(
self : Resource,
amount : Int,
priority : Int,
callback : (Bool) -> Unit,
) -> Int {
if amount <= 0 || amount > self.capacity {
abort("Invalid request amount for Resource")
}
let req_id = self.next_req_id
self.next_req_id = self.next_req_id + 1
if self.wait_queue.is_empty() && self.available >= amount {
self.available = self.available - amount
callback(true)
req_id
} else {
let req = { id: req_id, amount, priority, callback, cancelled: false }
// Insert into wait queue ordered by priority (lower number = higher priority)
let mut insert_idx = self.wait_queue.length()
for i = 0; i < self.wait_queue.length(); i = i + 1 {
if self.wait_queue[i].priority > priority {
insert_idx = i
break
}
}
self.wait_queue.insert(insert_idx, req)
req_id
}
}
///|
pub fn Resource::cancel_request(self : Resource, req_id : Int) -> Bool {
let mut found = false
for i = 0; i < self.wait_queue.length(); i = i + 1 {
if self.wait_queue[i].id == req_id && !self.wait_queue[i].cancelled {
self.wait_queue[i].cancelled = true
found = true
break
}
}
self.clean_cancelled()
found
}
///|
fn Resource::clean_cancelled(self : Resource) -> Unit {
let mut idx = 0
while idx < self.wait_queue.length() {
if self.wait_queue[idx].cancelled {
let _ = self.wait_queue.remove(idx)
} else {
idx = idx + 1
}
}
}
///|
pub fn Resource::release(self : Resource, amount : Int) -> Unit {
if amount <= 0 {
abort("Release amount must be positive")
}
if self.available + amount > self.capacity {
abort("Release exceeds capacity of Resource \{self.name}")
}
self.available = self.available + amount
self.process_queue()
}
///|
fn Resource::process_queue(self : Resource) -> Unit {
self.clean_cancelled()
while !self.wait_queue.is_empty() {
let top = self.wait_queue[0]
if self.available >= top.amount {
self.available = self.available - top.amount
let _ = self.wait_queue.remove(0)
(top.callback)(true)
} else {
break
}
}
}