weave_draft/
lib.rs

1#![warn(missing_docs)]
2#![warn(clippy::pedantic)]
3
4//! # weave-draft
5//!
6//! `weave-draft` is a crate for representing and manipulating weaving drafts
7//!
8//! ## Crate features
9//!
10//! ### `wif`
11//!
12//! Enable this to convert to the standard `.wif` format
13
14use crate::data::{Shaft, Treadle, YarnSequence};
15#[doc(inline)]
16pub use data::RiseSink;
17#[doc(inline)]
18pub use data::Threading;
19#[doc(inline)]
20pub use data::TieUp;
21#[doc(inline)]
22pub use data::TieUpCreate;
23#[doc(inline)]
24pub use data::TieUpKind;
25#[doc(inline)]
26pub use data::TreadlingInfo;
27#[doc(inline)]
28pub use data::Yarn;
29#[doc(inline)]
30pub use data::YarnPalette;
31use std::cmp::Ordering;
32use std::collections::HashSet;
33use std::ops::RangeBounds;
34use std::rc::Rc;
35
36pub mod data;
37
38/// Structure holding all elements of a draft
39#[derive(Clone, Debug, PartialEq)]
40pub struct Draft {
41    threading: Threading,
42    treadling: TreadlingInfo,
43    yarn_palette: YarnPalette,
44    weft_yarns: YarnSequence,
45    warp_yarns: YarnSequence,
46}
47
48/// An enum representing the axes of a weaving draft
49pub enum WeavingAxis {
50    /// Threading
51    Threading,
52    /// Treadling
53    Treadling,
54}
55
56impl Draft {
57    /// Create an empty draft with the given options
58    #[must_use]
59    pub fn new(shaft_count: u32, tie_up_create: TieUpCreate, rise_sink: RiseSink) -> Self {
60        Self {
61            threading: Threading::new(shaft_count, Vec::new()),
62            treadling: TreadlingInfo::new(shaft_count, tie_up_create, rise_sink),
63            yarn_palette: YarnPalette::default(),
64            weft_yarns: YarnSequence::default(),
65            warp_yarns: YarnSequence::default(),
66        }
67    }
68
69    /// Get the threading
70    #[must_use]
71    pub fn threading(&self) -> &Threading {
72        &self.threading
73    }
74
75    /// Get the treadling
76    #[must_use]
77    pub fn treadling_info(&self) -> &TreadlingInfo {
78        &self.treadling
79    }
80
81    /// Get the tie-up
82    #[must_use]
83    pub fn tie_up(&self) -> &TieUpKind {
84        self.treadling.tie_up()
85    }
86
87    /// Make rising shaft
88    pub fn make_rising(&mut self) {
89        self.treadling.make_rising();
90    }
91
92    /// Make sinking shaft
93    pub fn make_sinking(&mut self) {
94        self.treadling.make_sinking();
95    }
96
97    /// Goes from a treadling to a lift plan. Returns false if already a lift plan,
98    /// true if conversion happened
99    pub fn make_lift_plan(&mut self) -> bool {
100        self.treadling.make_lift_plan()
101    }
102
103    /// Max shaft used in threading or treadling
104    #[must_use]
105    pub fn max_shaft(&self) -> (WeavingAxis, u32) {
106        let treadling_max = self.treadling.max_shaft_used();
107        let threading_max = self.threading.max_shaft();
108
109        match treadling_max.cmp(&threading_max) {
110            Ordering::Less | Ordering::Equal => (WeavingAxis::Threading, threading_max),
111            Ordering::Greater => (WeavingAxis::Treadling, treadling_max),
112        }
113    }
114
115    /// Sets shaft count on threading and treadling. Only succeeds when non-destructive
116    ///
117    /// # Errors
118    /// If shafts greater than the given count are in use, returns an error with the max used shaft
119    /// and the axis it's used on
120    ///
121    /// # Panics
122    /// If shaft count is 0
123    pub fn set_shaft_count(&mut self, shaft_count: u32) -> Result<(), (WeavingAxis, u32)> {
124        let (axis, max) = self.max_shaft();
125        if shaft_count >= max {
126            self.treadling.set_shaft_count(shaft_count).unwrap();
127            self.threading.set_shaft_count(shaft_count).unwrap();
128            Ok(())
129        } else {
130            Err((axis, max))
131        }
132    }
133
134    /// Calls [`Threading::splice`]
135    ///
136    /// # Errors
137    /// See [`Threading::splice`]
138    pub fn splice_threading<R>(&mut self, range: R, replace_with: &[u32]) -> Result<Vec<u32>, usize>
139    where
140        R: RangeBounds<usize>,
141    {
142        self.threading.splice(range, replace_with)
143    }
144
145    /// Adds a new thread to teh end of the threading
146    ///
147    /// # Errors
148    /// Returns the shaft if greater than shaft count
149    pub fn push_threading(&mut self, shaft: u32) -> Result<(), u32> {
150        self.threading.push(shaft)
151    }
152
153    /// Insert a thread in the threading at the given index, shifting the later threads
154    ///
155    /// # Panics
156    /// If index is greater than length
157    ///
158    /// # Errors
159    /// If `shaft` is greater than `shaft_count`
160    pub fn insert_threading(&mut self, shaft: Shaft, index: usize) -> Result<(), Shaft> {
161        self.threading.insert(shaft, index)
162    }
163
164    /// Insert a thread at the given index, shifting later threads
165    ///
166    /// # Errors
167    /// Returns the current length if index is greater than length
168    pub fn try_insert_threading(
169        &mut self,
170        shaft: Shaft,
171        index: usize,
172    ) -> Result<Result<(), Shaft>, usize> {
173        self.threading.try_insert(shaft, index)
174    }
175
176    /// Remove the thread at the given index, returning it as a [Shaft]
177    ///
178    /// # Panics
179    /// If index is out of bounds
180    pub fn remove_threading(&mut self, index: usize) -> Shaft {
181        self.threading.remove(index)
182    }
183
184    /// Get threading shaft at an index
185    #[must_use]
186    pub fn get_from_threading(&self, index: usize) -> Option<&u32> {
187        self.threading.get(index)
188    }
189
190    /// Overwrite thread at given index, returns old thread value
191    ///
192    /// # Panics
193    /// If index is out of bounds
194    pub fn put_threading(&mut self, index: usize, shaft: Shaft) -> Shaft {
195        self.threading.put(index, shaft)
196    }
197
198    /// Overwrite thread at given index. Returns replaced shaft, or none if inserting at the end
199    ///
200    /// # Errors
201    ///
202    /// Returns current length if index out of bounds
203    pub fn try_put_threading(
204        &mut self,
205        index: usize,
206        shaft: Shaft,
207    ) -> Result<Option<Shaft>, usize> {
208        self.threading.try_put(index, shaft)
209    }
210
211    /// See [`Threading::flip_vertical`]
212    pub fn flip_threading_vert(&mut self) {
213        self.threading.flip_vertical();
214    }
215
216    /// See [`Threading::mirror`]
217    pub fn mirror_threading(&mut self) {
218        self.threading.mirror();
219    }
220
221    /// See [`Threading::reverse`]
222    pub fn flip_threading_horiz(&mut self) {
223        self.threading.reverse();
224    }
225
226    /// Add a new pick at the end using just the given treadle
227    ///
228    /// # Errors
229    /// If treadle is higher than number of shafts, returns treadle
230    pub fn push_single_treadling(&mut self, treadle: u32) -> Result<(), u32> {
231        self.treadling.push_single(treadle)
232    }
233
234    /// Add a new pick at the end using all given treadles/shafts
235    ///
236    /// # Errors
237    /// If any treadle is over the number of treadles/shafts, returns that value
238    pub fn push_treadling(&mut self, treadles: HashSet<u32>) -> Result<(), u32> {
239        self.treadling.push(treadles)
240    }
241
242    /// Toggle treadle at given index. Return `true` if treadle has been toggled on, `false` if toggled off
243    ///
244    /// # Errors
245    /// If treadle is invalid
246    /// # Panics
247    /// If index is out of bounds
248    pub fn toggle_treadle(&mut self, index: usize, treadle: Treadle) -> Result<bool, u32> {
249        self.treadling.toggle_treadle(index, treadle)
250    }
251
252    /// Inserts treadling at given index
253    ///
254    /// # Errors
255    /// If any treadles are invalid
256    /// # Panics
257    /// If index is out of bounds
258    pub fn insert_treadle(&mut self, index: usize, treadles: HashSet<u32>) -> Result<(), u32> {
259        self.treadling.insert(index, treadles)
260    }
261
262    /// Based on [`Vec::splice`], it splices the given sequence into the given range. It validates that
263    /// the elements in `replace_with` are inside the shaft bounds, and it returns the replaced elements.
264    ///
265    /// # Errors
266    /// If an element in `replace_with` is larger than the shaft count, returns index of first
267    /// out-of-bounds element
268    pub fn splice_treadling<R>(
269        &mut self,
270        range: R,
271        replace_with: Vec<HashSet<u32>>,
272    ) -> Result<Vec<HashSet<u32>>, u32>
273    where
274        R: RangeBounds<usize>,
275    {
276        self.treadling.splice(range, replace_with)
277    }
278    /// Overwrites the treadling at the given index with the new treadles
279    ///
280    /// # Errors
281    /// If treadling is invalid
282    ///
283    /// # Panics
284    /// If index is greater than the length of the treadling
285    pub fn put_treadling(
286        &mut self,
287        index: usize,
288        treadles: HashSet<u32>,
289    ) -> Result<Option<HashSet<u32>>, u32> {
290        self.treadling.put(index, treadles)
291    }
292
293    /// Get yarn palette
294    #[must_use]
295    pub fn yarn_palette(&self) -> &YarnPalette {
296        &self.yarn_palette
297    }
298
299    /// Get weft yarns
300    #[must_use]
301    pub fn weft_yarns(&self) -> &YarnSequence {
302        &self.weft_yarns
303    }
304
305    /// Get warp yarns
306    #[must_use]
307    pub fn warp_yarns(&self) -> &YarnSequence {
308        &self.warp_yarns
309    }
310
311    /// Set the repeat of weft yarns
312    pub fn set_weft_yarn_repeat<T>(&mut self, yarns: T)
313    where
314        T: IntoIterator<Item = Yarn>,
315    {
316        let yarns = self.yarn_palette.use_yarns(yarns);
317        self.weft_yarns.set_repeat(&yarns);
318    }
319
320    /// set weft yarn repeat offset
321    pub fn set_weft_yarn_offset(&mut self, offset: usize) {
322        self.weft_yarns.set_offset(offset);
323    }
324
325    /// set weft yarn at index
326    pub fn set_weft_yarn(&mut self, index: usize, yarn: Yarn) {
327        let yarn = self.yarn_palette.use_yarn(yarn);
328        self.weft_yarns.set_yarn(index, yarn);
329    }
330
331    /// Get weft yarn at index. Returns `None` if not set via repeat or directly
332    #[must_use]
333    pub fn try_get_weft_yarn(&self, index: usize) -> Option<&Rc<Yarn>> {
334        self.weft_yarns.try_get(index)
335    }
336
337    /// Get weft yarn at index
338    /// # Panics
339    /// If yarn is not set via repeat or directly
340    #[must_use]
341    pub fn get_weft_yarn(&self, index: usize) -> &Rc<Yarn> {
342        self.weft_yarns.get(index)
343    }
344
345    /// Set the repeat of weft yarns
346    pub fn set_warp_yarn_repeat<T>(&mut self, yarns: T)
347    where
348        T: IntoIterator<Item = Yarn>,
349    {
350        let yarns = self.yarn_palette.use_yarns(yarns);
351        self.warp_yarns.set_repeat(&yarns);
352    }
353
354    /// set warp yarn repeat offset
355    pub fn set_warp_yarn_offset(&mut self, offset: usize) {
356        self.warp_yarns.set_offset(offset);
357    }
358
359    /// set warp yarn at index
360    pub fn set_warp_yarn(&mut self, index: usize, yarn: Yarn) {
361        let yarn = self.yarn_palette.use_yarn(yarn);
362        self.warp_yarns.set_yarn(index, yarn);
363    }
364
365    /// Get warp yarn at index. Returns `None` if not set via repeat or directly
366    #[must_use]
367    pub fn try_get_warp_yarn(&self, index: usize) -> Option<&Rc<Yarn>> {
368        self.warp_yarns.try_get(index)
369    }
370
371    /// Get warp yarn at index
372    /// # Panics
373    /// If yarn is not set via repeat or directly
374    #[must_use]
375    pub fn get_warp_yarn(&self, index: usize) -> &Rc<Yarn> {
376        self.warp_yarns.get(index)
377    }
378}