// Copyright 2015 The etcd Authors
// Copyright 2026 Leo Cheng
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// The batch of outstanding work the application must handle for one turn of the
/// state machine (etcd's `Ready`). The contract is synchronous, not a coroutine:
/// the caller persists `entries`/`hard_state`/`snapshot`, sends `messages`,
/// applies `committed_entries`, serves `read_states`, then calls `advance`.
///
/// A field carries work only when there is some: `soft_state` and `hard_state`
/// are `Some` only on change (expressed as `Option`, not a sentinel), and the
/// arrays are empty when idle. `must_sync` says whether the persist must be a
/// durable (fsync) write or may be lazily flushed.
pub(all) struct Ready {
soft_state : SoftState?
hard_state : HardState?
read_states : Array[ReadState]
entries : Array[Entry]
snapshot : Snapshot?
committed_entries : Array[Entry]
messages : Array[Message]
must_sync : Bool
// Local storage directives, populated only under AsyncStorageWrites. Instead
// of the caller persisting `entries` / applying `committed_entries` inline and
// then calling `advance`, the work is handed to a local storage thread as a
// directive; the thread does it and delivers the paired response back through
// `step_append_resp` / `step_apply_resp`. `None` in the synchronous mode.
storage_append : StorageAppend?
storage_apply : StorageApply?
}
///|
/// A directive to the local append thread: write these unstable entries (and the
/// hard state / snapshot, if present) to stable storage, then return `resp`
/// (etcd's `MsgStorageAppend`).
pub(all) struct StorageAppend {
entries : Array[Entry]
hard_state : HardState?
snapshot : Snapshot?
resp : StorageAppendResp
// Responses that were waiting for this append to be durable (etcd's
// `MsgStorageAppend.Responses`): the candidate's own vote, the leader's
// acknowledgement of its own entries, and the append acknowledgement itself.
// The storage thread steps them once the write completes, which is what keeps
// a vote from being published before it is on disk.
responses : Array[Message]
}
///|
/// A directive to the local apply thread: apply these committed entries to the
/// state machine, then return `resp` (etcd's `MsgStorageApply`).
pub(all) struct StorageApply {
entries : Array[Entry]
resp : StorageApplyResp
}
///|
/// Whether a synchronous durable write is required before replying to any RPC
/// (etcd's `MustSync`). The persistent state on every server — currentTerm,
/// votedFor, and the log — must be flushed when new entries are appended or the
/// term or vote changed; a bare commit-index bump may be flushed lazily (§5).
pub fn must_sync(hs : HardState, prev : HardState, entries_num : Int32) -> Bool {
entries_num != 0 || hs.vote != prev.vote || hs.term != prev.term
}