Current section

Files

Jump to
puddle src puddle.gleam
Raw

src/puddle.gleam

import gleam/list
import gleam/otp/actor
import gleam/erlang/process
pub opaque type Puddle(resource_type, result_type) {
Puddle(
idle: List(#(Int, process.Subject(Message(resource_type, result_type)))),
busy: List(#(Int, process.Subject(Message(resource_type, result_type)))),
)
}
pub type Message(resource_type, result_type) {
Shutdown
Utilize(
fn(resource_type) -> result_type,
reply_with: process.Subject(result_type),
)
}
pub fn new(size: Int, new_resource: fn() -> Result(resource_type, Nil)) {
case
list.repeat("", size)
|> list.index_map(fn(index, _) { index })
|> list.try_map(fn(index) {
case new_resource() {
Ok(initial_state) -> {
let assert Ok(subject) =
actor.start(
initial_state,
fn(
msg: Message(resource_type, result_type),
resource: resource_type,
) {
case msg {
Shutdown -> actor.Stop(process.Normal)
Utilize(func, client) -> {
let result = func(resource)
actor.send(client, result)
actor.continue(resource)
}
}
},
)
#(index, subject)
|> Ok
}
Error(Nil) -> Error(Nil)
}
})
{
Ok(idle) ->
Puddle(idle, [])
|> Ok
Error(Nil) -> Error(Nil)
}
}
pub fn checkout(puddle) {
case puddle {
Puddle(idle, busy) ->
case idle {
[#(id, subject), ..rest] ->
Ok(#(#(id, subject), Puddle(rest, list.prepend(busy, #(id, subject)))))
[] -> Error(Nil)
}
}
}
pub fn put_back(puddle, subject_id) {
case puddle {
Puddle(idle, busy) -> {
let assert Ok(#(subject, busy)) = list.key_pop(busy, subject_id)
Puddle(list.key_set(idle, subject_id, subject), busy)
}
}
}