///|
/// Loom limits are advisory engineering constraints, not fabric safety certification.
pub(all) struct LoomLimits {
shafts : Int
raised : Int
float_length : Int
} derive(Eq, Debug)
///|
pub(all) struct Finding {
code : String
pick : Int
thread : Int
shaft : Int?
direction : Direction?
back : Bool?
} derive(Eq, Debug, ToJson, FromJson)
///|
pub fn Draft::check_loom(
self : Draft,
limits : LoomLimits,
) -> Result[Array[Finding], String] {
if limits.shafts < 1 ||
limits.raised < 0 ||
limits.float_length < 1 ||
limits.float_length > 2048 {
return Err("weave.limits")
}
let out : Array[Finding] = []
if self.shafts > limits.shafts {
out.push({
code: "loom.shaft_capacity",
pick: -1,
thread: -1,
shaft: None,
direction: None,
back: None,
})
}
for p, lift in self.lifts {
if lift.length() > limits.raised {
out.push({
code: "loom.raised_capacity",
pick: p,
thread: -1,
shaft: None,
direction: None,
back: None,
})
}
let visible = self.threading.filter(fn(s) { lift.contains(s) }).length()
if visible == 0 || visible == self.width() {
out.push({
code: "loom.closed_shed",
pick: p,
thread: -1,
shaft: None,
direction: None,
back: None,
})
}
}
for s = 1; s <= self.shafts; s = s + 1 {
if !self.threading.contains(s) {
out.push({
code: "loom.unused_shaft",
pick: -1,
thread: -1,
shaft: Some(s),
direction: None,
back: None,
})
}
}
for back in [false, true] {
match self.periodic_floats(limits.float_length + 1, back~) {
Ok(runs) =>
for r in runs {
out.push({
code: if r.unbounded {
"loom.unbound_thread"
} else {
"loom.long_float"
},
pick: if r.run.direction == Warp {
r.run.start
} else {
r.run.thread
},
thread: if r.run.direction == Warp {
r.run.thread
} else {
r.run.start
},
shaft: None,
direction: Some(r.run.direction),
back: Some(back),
})
}
Err(_) => ()
}
}
Ok(out)
}