///|
pub(all) enum BuildDecision {
UpToDate
NeedsBuild(String)
} derive(Debug, Eq)
///|
pub fn BuildEdge::evaluate_incremental(
self : BuildEdge,
snapshot : Map[String, Int],
) -> BuildDecision {
if self.outputs.is_empty() {
return NeedsBuild("edge has no outputs")
}
let mut newest_input = 0
let mut has_input = false
for input in self.inputs {
match snapshot.get(input) {
Some(stamp) =>
if !has_input || stamp > newest_input {
newest_input = stamp
has_input = true
}
None => return NeedsBuild("missing input: " + input)
}
}
let mut oldest_output = 0
let mut has_output = false
for output in self.outputs {
match snapshot.get(output) {
Some(stamp) =>
if !has_output || stamp < oldest_output {
oldest_output = stamp
has_output = true
}
None => return NeedsBuild("missing output: " + output)
}
}
if !has_input {
return UpToDate
}
if newest_input > oldest_output {
return NeedsBuild("outputs are older than at least one input")
}
UpToDate
}
///|
/// Compare current filesystem fingerprints with the previous build state.
///
/// This check intentionally combines content identity and MTime ordering:
/// equal timestamps do not hide changed content, and newer inputs still make
/// older outputs stale.
pub fn BuildEdge::evaluate_fingerprints(
self : BuildEdge,
current : Map[String, FileFingerprint],
previous : Map[String, FileFingerprint],
) -> BuildDecision {
if self.outputs.is_empty() {
return NeedsBuild("edge has no outputs")
}
for input in self.inputs {
match current.get(input) {
None => return NeedsBuild("missing input: " + input)
Some(now) =>
match previous.get(input) {
None =>
return NeedsBuild("input has no previous fingerprint: " + input)
Some(before) =>
if now != before {
return NeedsBuild("input changed: " + input)
}
}
}
}
for output in self.outputs {
match current.get(output) {
None => return NeedsBuild("missing output: " + output)
Some(now) =>
match previous.get(output) {
None =>
return NeedsBuild("output has no previous fingerprint: " + output)
Some(before) =>
if now != before {
return NeedsBuild("output changed externally: " + output)
}
}
}
}
for input in self.inputs {
match current.get(input) {
Some(input_fingerprint) =>
for output in self.outputs {
match current.get(output) {
Some(output_fingerprint) =>
if input_fingerprint.is_newer_than(output_fingerprint) {
return NeedsBuild("outputs are older than input: " + input)
}
None => return NeedsBuild("missing output: " + output)
}
}
None => return NeedsBuild("missing input: " + input)
}
}
UpToDate
}
///|
pub fn BuildEdge::refresh_outputs(
self : BuildEdge,
snapshot : Map[String, Int],
tick : Int,
) -> Int {
let mut next_tick = tick
for input in self.inputs {
match snapshot.get(input) {
Some(stamp) => if stamp >= next_tick { next_tick = stamp + 1 }
None => ()
}
}
for output in self.outputs {
snapshot[output] = next_tick
}
next_tick + 1
}