///|
/// Lockwire core package.
///|
pub fn package_id() -> String {
"lockwire/core"
}
///|
pub(all) enum Duration {
Duration(Int64)
} derive(Eq, Debug, Compare)
///|
pub fn Duration::from_ns(ns : Int64) -> Duration {
Duration(ns)
}
///|
pub fn Duration::ns(self : Duration) -> Int64 {
match self {
Duration(ns) => ns
}
}
///|
pub(all) enum VTime {
VTime(Int64)
} derive(Eq, Debug, Compare)
///|
pub fn VTime::from_ns(ns : Int64) -> VTime {
VTime(ns)
}
///|
pub fn VTime::ns(self : VTime) -> Int64 {
match self {
VTime(ns) => ns
}
}
///|
pub fn VTime::add(self : VTime, delta : Duration) -> VTime {
VTime(self.ns() + delta.ns())
}
///|
pub(all) enum EndpointId {
EndpointId(Int)
} derive(Eq, Debug, Compare)
///|
pub fn EndpointId::value(self : EndpointId) -> Int {
match self {
EndpointId(value) => value
}
}
///|
pub(all) enum ChannelId {
ChannelId(Int)
} derive(Eq, Debug, Compare)
///|
pub fn ChannelId::value(self : ChannelId) -> Int {
match self {
ChannelId(value) => value
}
}
///|
pub(all) struct Channel {
id : ChannelId
next_seq : Int
} derive(Eq, Debug)
///|
pub fn Channel::new(id~ : ChannelId) -> Channel {
{ id, next_seq: 1 }
}
///|
pub fn Channel::reserve(self : Channel) -> (Channel, Int) {
({ id: self.id, next_seq: self.next_seq + 1 }, self.next_seq)
}
///|
pub(all) enum PortId {
PortId(Int)
} derive(Eq, Debug, Compare)
///|
pub(all) suberror TransportError {
LinkDown
InvalidFrame(String)
UnboundEndpoint(EndpointId)
} derive(Debug)
///|
pub(all) enum FrameState {
Free
Acquired
Filled
Sending
Sent
Receiving
Received
Released
} derive(Eq, Debug)
///|
pub(all) struct Frame {
id : Int
payload : Bytes
state : FrameState
} derive(Eq, Debug)
///|
pub fn Frame::acquire(id~ : Int) -> Frame {
{ id, payload: b"", state: Acquired }
}
///|
pub fn Frame::filled(self : Frame, payload~ : Bytes) -> Frame {
{ id: self.id, payload, state: Filled }
}
///|
pub fn Frame::sending(self : Frame) -> Frame {
{ id: self.id, payload: self.payload, state: Sending }
}
///|
pub fn Frame::sent(self : Frame) -> Frame {
{ id: self.id, payload: self.payload, state: Sent }
}
///|
pub fn Frame::receiving(self : Frame) -> Frame {
{ id: self.id, payload: self.payload, state: Receiving }
}
///|
pub fn Frame::received(self : Frame) -> Frame {
{ id: self.id, payload: self.payload, state: Received }
}
///|
pub fn Frame::released(self : Frame) -> Frame {
{ id: self.id, payload: self.payload, state: Released }
}
///|
pub(all) struct TxEvent {
id : Int
parent_id : Int?
vtime : VTime
channel_id : ChannelId
seq : Int
source : EndpointId
target : EndpointId
frame : Frame
} derive(Eq, Debug)
///|
pub fn TxEvent::make(
id~ : Int,
parent_id? : Int,
vtime~ : VTime,
channel_id~ : ChannelId,
seq~ : Int,
source~ : EndpointId,
target~ : EndpointId,
frame~ : Frame,
) -> TxEvent {
{ id, parent_id, vtime, channel_id, seq, source, target, frame }
}
///|
pub(all) struct RxEvent {
id : Int
parent_id : Int
vtime : VTime
channel_id : ChannelId
seq : Int
source : EndpointId
target : EndpointId
frame : Frame
} derive(Eq, Debug)
///|
pub(all) struct LinearizationKey {
vtime : VTime
channel_id : ChannelId
seq : Int
parent_sort : Int
event_id : Int
} derive(Eq, Debug, Compare)
///|
pub fn TxEvent::linearization_key(self : TxEvent) -> LinearizationKey {
let parent_sort = match self.parent_id {
Some(id) => id
None => -1
}
{
vtime: self.vtime,
channel_id: self.channel_id,
seq: self.seq,
parent_sort,
event_id: self.id,
}
}
///|
pub fn tx_event_precedes(left : TxEvent, right : TxEvent) -> Bool {
left.linearization_key() <= right.linearization_key()
}
///|
pub fn rx_event_precedes(left : RxEvent, right : RxEvent) -> Bool {
(left.vtime, left.channel_id, left.seq, left.parent_id, left.id) <=
(right.vtime, right.channel_id, right.seq, right.parent_id, right.id)
}
///|
pub fn check_rx_invariants(events : ArrayView[RxEvent]) -> Bool {
for i in 0.. current.id {
return false
}
for j in 0.. current.seq {
return false
}
}
}
true
}
///|
pub(all) struct SimDigest {
state_digest : Int64
rng_steps : Int
event_count : Int
} derive(Eq, Debug)
///|
pub fn SimDigest::empty(seed~ : Int) -> SimDigest {
{ state_digest: Int64::from_int(seed), rng_steps: 0, event_count: 0 }
}
///|
pub fn SimDigest::mix(self : SimDigest, value : Int) -> SimDigest {
{
state_digest: self.state_digest * 131L + Int64::from_int(value),
rng_steps: self.rng_steps,
event_count: self.event_count + 1,
}
}
///|
pub fn SimDigest::step_rng(self : SimDigest) -> SimDigest {
{
state_digest: self.state_digest,
rng_steps: self.rng_steps + 1,
event_count: self.event_count,
}
}
///|
pub(open) trait Endpoint {
fn on_rx(Self, RxEvent) -> Unit
fn on_tick(Self, VTime) -> Unit
}
///|
pub(open) trait Medium {
fn submit(Self, TxEvent) -> Array[RxEvent] raise TransportError
fn lookahead(Self) -> Duration
}
///|
pub(open) trait PointToPointMedium: Medium {
fn bind(Self, EndpointId, EndpointId) -> Unit
}
///|
pub(open) trait Reactor {
fn now(Self) -> VTime
fn schedule(Self, TxEvent) -> Unit raise TransportError
fn run(Self) -> SimDigest raise TransportError
}
///|
pub(all) enum MvpStage {
M0Skeleton
M1CoreP2p
M2ScenarioEvent
M3TraceReplay
M4FaultResource
M5NativeWasmDiff
M6SegmentToy
M7Packaging
} derive(Debug, Eq)
///|
pub fn mvp_stages() -> Array[MvpStage] {
[
M0Skeleton,
M1CoreP2p,
M2ScenarioEvent,
M3TraceReplay,
M4FaultResource,
M5NativeWasmDiff,
M6SegmentToy,
M7Packaging,
]
}
///|
pub fn mvp_stage_label(stage : MvpStage) -> String {
match stage {
M0Skeleton => "M0 Skeleton"
M1CoreP2p => "M1 Core+P2P"
M2ScenarioEvent => "M2 Scenario/Event"
M3TraceReplay => "M3 Trace+Replay"
M4FaultResource => "M4 Fault+Resource"
M5NativeWasmDiff => "M5 Native/Wasm Diff"
M6SegmentToy => "M6 Segment Toy"
M7Packaging => "M7 Packaging"
}
}
///|
pub(all) enum BackendProfile {
SimNative
SimWasm
Replay
RealLinux
RealEmbedded
} derive(Debug, Eq)
///|
pub fn backend_profiles() -> Array[BackendProfile] {
[SimNative, SimWasm, Replay, RealLinux, RealEmbedded]
}
///|
pub fn backend_profile_label(profile : BackendProfile) -> String {
match profile {
SimNative => "sim-native"
SimWasm => "sim-wasm"
Replay => "replay"
RealLinux => "real-linux"
RealEmbedded => "real-embedded"
}
}
///|
pub fn BackendProfile::is_deterministic(profile : BackendProfile) -> Bool {
match profile {
SimNative => true
SimWasm => true
Replay => true
RealLinux => false
RealEmbedded => false
}
}