///|
pub fn limits_to_json(limits : Limits) -> Json {
{
"buffered_events": Json::number(limits.buffered_events.to_double()),
"active_states": Json::number(limits.active_states.to_double()),
"partitions": Json::number(limits.partitions.to_double()),
"outputs_per_call": Json::number(limits.outputs_per_call.to_double()),
"work_per_call": Json::number(limits.work_per_call.to_double()),
}
}
///|
pub fn limits_from_json(value : Json) -> Limits raise CepError {
let object = codec_object(value, "limits")
codec_keys(
object,
[
"buffered_events", "active_states", "partitions", "outputs_per_call", "work_per_call",
],
"limits",
)
let limits : Limits = {
buffered_events: codec_int32(
codec_required(object, "buffered_events", "limits"),
"limits.buffered_events",
),
active_states: codec_int32(
codec_required(object, "active_states", "limits"),
"limits.active_states",
),
partitions: codec_int32(
codec_required(object, "partitions", "limits"),
"limits.partitions",
),
outputs_per_call: codec_int32(
codec_required(object, "outputs_per_call", "limits"),
"limits.outputs_per_call",
),
work_per_call: codec_int32(
codec_required(object, "work_per_call", "limits"),
"limits.work_per_call",
),
}
limits.validate()
limits
}
///|
pub fn session_to_json(session : Session) -> Json {
{
"schema_version": 1,
"patterns": Json::array(session.engine.patterns.map(pattern_to_json)),
"limits": limits_to_json(session.engine.limits),
"max_commands": Json::number(session.max_commands.to_double()),
"commands": Json::array(session.commands.map(command_to_json)),
}
}
///|
/// Restore by validating and replaying committed inputs. max_work is a total
/// import budget, in addition to each engine advance's own work limit.
pub fn session_from_json(
value : Json,
max_work~ : Int32 = 10000000,
) -> Session raise CepError {
if max_work < 1 || max_work > 100000000 {
raise Invalid(path="restore.max_work", reason="expected 1..100000000")
}
let object = codec_object(value, "session")
codec_keys(
object,
["schema_version", "patterns", "limits", "max_commands", "commands"],
"session",
)
if codec_int32(
codec_required(object, "schema_version", "session"),
"session.schema_version",
) !=
1 {
raise Invalid(
path="session.schema_version",
reason="only version 1 is supported",
)
}
let limits = limits_from_json(codec_required(object, "limits", "session"))
let max_commands = codec_int32(
codec_required(object, "max_commands", "session"),
"session.max_commands",
)
let patterns_json = codec_array(
codec_required(object, "patterns", "session"),
"session.patterns",
)
if patterns_json.length() > 64 {
raise Resource(resource="patterns", limit=64)
}
let patterns = patterns_json.map(pattern_from_json)
let session = Session::new(patterns, limits~, max_commands~)
let commands = codec_array(
codec_required(object, "commands", "session"),
"session.commands",
)
if commands.length() > max_commands {
raise Resource(resource="journal commands", limit=max_commands)
}
let work = Work::{ used: 0, limit: max_work, }
for item in commands {
work.charge()
let command = command_from_json(item)
match session.apply(command) {
Accepted(_) => ()
Progress(batch) => work.charge(amount=batch.work)
}
}
session
}
///|
pub fn format_session(session : Session) -> String raise CepError {
codec_bounded_format(session_to_json(session))
}
///|
pub fn parse_session(
text : String,
max_work~ : Int32 = 10000000,
) -> Session raise CepError {
session_from_json(codec_parse(text, max_depth=128), max_work~)
}