letter_sequence/sequence/
builder.rs

1use crate::sequence::helper::*;
2use std::convert::From;
3use std::convert::TryFrom;
4use super::*;
5
6/// ```rust
7/// use letter_sequence::SequenceBuilder;
8/// use std::convert::TryFrom;
9///
10/// let mut seq = SequenceBuilder::try_from("Z")
11///   .unwrap()
12/// 	.upper()
13/// 	.build()
14/// 	.unwrap();
15/// // First call to .next() returns starting element
16/// let elem = seq.next().unwrap();
17/// assert_eq!( elem.to_string(), "Z" );
18/// let elem = seq.next().unwrap();
19/// assert_eq!( elem.to_string(), "AA" );
20/// let elem = seq.next().unwrap();
21/// assert_eq!( elem.to_string(), "AB" );
22/// let elem = seq.next().unwrap();
23/// assert_eq!( elem.to_string(), "AC" );
24/// ```
25///
26/// This time with .max_render_capacity() set, and lowercase
27/// ```rust
28/// use letter_sequence::SequenceBuilder;
29/// use std::convert::TryFrom;
30///
31/// let mut seq = SequenceBuilder::try_from('y')
32///   .unwrap()
33/// 	.lower()
34/// 	.max_render_capacity(1)
35/// 	.build()
36/// 	.unwrap();
37/// let elem = seq.next().unwrap();
38/// assert_eq!( elem.to_string(), "y"  );
39/// let elem = seq.next().unwrap();
40/// assert_eq!( elem.to_string(), "z"  );
41/// // Without .max_render_capacity(1) this would return "aa"
42/// let elem = seq.next();
43/// assert_eq!( elem, None  );
44/// ```
45///
46/// Also boring number sequence
47/// ```rust
48/// use letter_sequence::SequenceBuilder;
49/// use std::convert::TryFrom;
50///
51/// let mut seq = SequenceBuilder::from(102)
52/// 	.numeric()
53/// 	.build()
54/// 	.unwrap();
55/// let elem = seq.next();
56/// let elem = seq.next().unwrap();
57/// assert_eq!( elem.to_string(), "103" );
58/// ```
59///
60/// You can also set the step!
61/// ```rust
62/// use letter_sequence::SequenceBuilder;
63/// use std::convert::TryFrom;
64/// 
65/// let mut seq = SequenceBuilder::from(0)
66/// 	.numeric()
67/// 	.step(2)
68/// 	.build()
69/// 	.unwrap();
70/// let elem = seq.next().unwrap();
71/// assert_eq!( elem.to_string(), "0"  );
72/// let elem = seq.next().unwrap();
73/// assert_eq!( elem.to_string(), "2"  );
74/// let elem = seq.next().unwrap();
75/// assert_eq!( elem.to_string(), "4"  );
76///
77/// let mut seq = SequenceBuilder::try_from("A")
78///   .unwrap()
79/// 	.step(2)
80/// 	.upper()
81/// 	.build()
82/// 	.unwrap();
83/// let elem = seq.next().unwrap();
84/// assert_eq!( elem.to_string(), "A" );
85/// let elem = seq.next().unwrap();
86/// assert_eq!( elem.to_string(), "C" );
87/// let elem = seq.next().unwrap();
88/// assert_eq!( elem.to_string(), "E" );
89/// ```
90#[derive(Debug)]
91pub struct SequenceBuilder {
92	start: u64,
93	step: u32,
94	inclusive: bool,
95	renderer: SeqRendererBuilder,
96	min_render_length: Option<u8>,
97	end: Option<u64>
98}
99
100impl Default for SequenceBuilder {
101	fn default() -> Self {
102		Self {
103			start: 0,
104			step: 1,
105			end: None,
106			inclusive: false,
107			renderer: Default::default(),
108			min_render_length: Default::default(),
109		}
110	}
111}
112
113impl SequenceBuilder {
114	pub fn new() -> Self {
115		Self { ..Default::default() }
116	}
117
118
119	/// Sets the end, default half-open (exclusive end), see .inclusive()
120	pub fn end(mut self, end: u64) -> Self {
121		self.end = Some(end);
122		self
123	}
124	
125	/// Sets the start
126	pub fn start(mut self, start: u64) -> Self {
127		self.start = start;
128		self
129	}
130	
131	/// Sets the increment to step to
132	pub fn step(mut self, step: u32) -> Self {
133		self.step = step;
134		self
135	}
136
137
138	/// Limits the chacters in rendered output, incrementing past limit generates
139	/// error. default: unlimited
140	///
141	/// ```rust
142	/// use letter_sequence::{ SequenceBuilder, SequenceError };
143	/// use std::convert::TryFrom;
144	/// let mut seq = SequenceBuilder::try_from("y").unwrap().max_render_capacity(1).build().unwrap();
145	/// let elem = seq.next().unwrap();
146	/// assert_eq!( elem.to_string(), "y" );
147	/// let elem = seq.next().unwrap();
148	/// assert_eq!( elem.to_string(), "z" );
149	/// assert_eq!( seq.next(), None );
150	/// assert_eq!( seq.next(), None );
151	/// ```
152	pub fn max_render_capacity(mut self, chars: u8) -> Self {
153		self.renderer = self.renderer.capacity(chars);
154		self
155	}
156
157	/// Limits the minimum width of the rendered output, this only works on
158	/// numeric which effectively zero-pads the output.
159	pub fn min_render_length(mut self, chars: u8) -> Self {
160		self.min_render_length = Some(chars);
161		self
162	}
163
164	/// This is the default: a half-open range that excludes the end
165	pub fn exclusive(mut self) -> Self {
166		self.inclusive = false;
167		self
168	}
169	
170	/// Close the range, include the end
171	pub fn inclusive(mut self) -> Self {
172		self.inclusive = true;
173		self
174	}
175	
176	/// Render the sequence in lowercase
177	pub fn lower(mut self) -> Self {
178		self.renderer = SeqRendererBuilder::lower();
179		self
180	}
181	/// Render the sequence in uppercase, default
182	pub fn upper(mut self) -> Self {
183		self.renderer = SeqRendererBuilder::upper();
184		self
185	}
186	/// Render the sequence in digits
187	pub fn numeric(mut self) -> Self {
188		self.renderer = SeqRendererBuilder::numeric();
189		self
190	}
191
192	pub fn build(self) -> Result<Sequence, SequenceError> {
193		let renderer = self.renderer.build()?;
194
195		// You can't really pad alpha-numerics because A is not 0.
196		match (renderer.display(), self.min_render_length) {
197			(RenderDisplay::Upper | RenderDisplay::Lower, Some(_)) => return Err(SequenceError::PaddingAlpha),
198			_ => ()
199		};
200
201		let end = match (self.end, self.inclusive) {
202			(Some(end), true) => Some(end + 1),
203			(Some(end), false) => Some(end),
204			_ => None
205		};
206		let seq = Sequence {
207			end,
208			step: self.step,
209			start: self.start,
210			renderer,
211			.. Default::default()
212		};
213		Ok(seq)
214	}
215}
216
217impl From<u64> for SequenceBuilder {
218	fn from(start: u64) -> Self {
219		Self::new().start(start)
220	}
221}
222
223/// ```rust
224/// // use letter_sequence::SequenceBuilder;
225/// // use std::convert::TryFrom;
226///	// assert_eq!(
227///	// 	SequenceBuilder::try_from("00001")
228///	// 		.unwrap()
229///	// 		.build()
230///	// 		.unwrap()
231///	// 		.to_string(),
232///	// 	"1"
233///	// );
234///	// assert_eq!(
235///	// 	SequenceBuilder::try_from("00001")
236///	// 		.unwrap()
237///	// 		.upper()
238///	// 		.build()
239///	// 		.unwrap()
240///	// 		.to_string(),
241///	// 	"B"
242///	// );
243/// ```
244impl TryFrom<&str> for SequenceBuilder {
245	type Error = SequenceError;
246	fn try_from(value: &str) -> Result<Self, Self::Error> {
247		let first_char = value
248			.chars()
249			.next()
250			.ok_or_else( || SequenceError::EmptyString )?
251		;
252
253		match renderer::RenderDisplay::try_from(first_char)? {
254			renderer::RenderDisplay::Numeric => Ok(
255				Self::new().start(value.parse::<u64>()?).numeric()
256			),
257			renderer::RenderDisplay::Upper => Ok(
258				Self::new().start(string_to_int(&value)?).upper()
259			),
260			renderer::RenderDisplay::Lower => Ok(
261				Self::new().start(string_to_int(&value)?).lower()
262			)
263		}
264	}
265}
266
267impl TryFrom<(&str, &str)> for SequenceBuilder {
268	type Error = SequenceError;
269	fn try_from((start, end): (&str, &str)) -> Result<Self, Self::Error> {
270		let first_char = start
271			.chars()
272			.next()
273			.ok_or_else( || SequenceError::EmptyString )?
274		;
275
276		let builder = match renderer::RenderDisplay::try_from(first_char)? {
277			renderer::RenderDisplay::Numeric => {
278				Self::new()
279					.start(start.parse::<u64>()?)
280					.end(end.parse::<u64>()?)
281					.numeric()
282			},
283			renderer::RenderDisplay::Upper => {
284				Self::new()
285					.start(string_to_int(&start)?)
286					.end(string_to_int(&end)?)
287					.upper()
288			},
289			renderer::RenderDisplay::Lower => {
290				Self::new()
291					.start(string_to_int(&start)?)
292					.end(string_to_int(&end)?)
293					.lower()
294			}
295		};
296
297		Ok(builder)
298	}
299}
300
301impl TryFrom<char> for SequenceBuilder {
302	type Error = SequenceError;
303	fn try_from(value: char) -> Result<Self, Self::Error> {
304		Ok(Self::new().start(char_to_int(value)? as u64))
305	}
306}
307
308#[cfg(test)]
309mod test {
310	use super::*;
311
312	/// Test violations of the max_render_capacity system, ensure we return an error
313	fn max_render_capacity() {
314		// Test link between max_alpha(chars) and the OutOfRange
315		for limit in 1..10 {
316			let max = crate::sequence::renderer::max_alpha(limit);
317			let mut seq = SequenceBuilder::new().start(max)
318				.upper()
319				.max_render_capacity(limit)
320				.build()
321				.unwrap();
322			let render_as = "Z".repeat(limit as usize);
323			let elem = seq.next().unwrap();
324			assert_eq!( elem.to_string(), render_as );
325			let elem = seq.next();
326			assert_eq!( elem, None );
327			assert_eq!( seq.next(), None )
328		}
329
330		// Test max_numeric(chars) + 1 throws OutOfRange
331		for limit in 1..10 {
332			let max = crate::sequence::renderer::max_numeric(limit);
333			let mut seq = SequenceBuilder::new().start(max).numeric().max_render_capacity(limit).build().unwrap();
334			let render_as = "9".repeat(limit as usize);
335			assert_eq!( seq.to_string(), render_as, "Render {} as {}", max, render_as );
336			assert_eq!(
337				seq.next(),
338				None,
339				"Throw error with numeric char limit of {} which can only represent {}",
340					limit,
341					max
342			);
343			assert_eq!( seq.next(), None )
344		}
345	}
346
347	/// Test that the first element renders properly with .upper() .lower() and .numeric()
348	#[test]
349	fn simple() {
350		for c in 'A'..'Z' {
351			// upper
352			let mut seq = SequenceBuilder::new().start(c as u64 - 'A' as u64).upper().build().unwrap();
353			let elem = seq.next().unwrap();
354			assert_eq!(
355				elem.to_string(),
356				c.to_string(),
357			);
358
359			// lower
360			let mut seq = SequenceBuilder::new().start(c as u64 - 'A' as u64).lower().build().unwrap();
361			let elem = seq.next().unwrap();
362			assert_eq!(
363				elem.to_string(),
364				c.to_string().to_lowercase(),
365			);
366		}
367
368		// numeric
369		for i in 1..123_456 {
370			let mut seq = SequenceBuilder::new().start(i).numeric().build().unwrap();
371			let elem = seq.next().unwrap();
372			assert_eq!(
373				elem.to_string(),
374				i.to_string()
375			);
376		}
377	}
378
379	fn rollover() {
380		const A: u32  = 0;
381		const Z: u32 = 25;
382		for i in A..Z {
383
384			// Easy check for A[A-Z] after Z
385			let seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
386			let result = format!("A{}", std::char::from_u32('A' as u32 + i).unwrap());
387			assert_eq!(
388				seq.skip(i as usize + 1).next().unwrap().to_string(),
389				result
390			);
391			
392			let mut seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
393			assert_eq!(
394				seq.nth(i as usize + 1).unwrap().to_string(),
395				result,
396				".nth({})", i
397			);
398
399			let seq = SequenceBuilder::new().start(Z as u64 + 1 + i as u64).lower().build().unwrap();
400			assert_eq!(
401				seq.to_string(),
402				result.to_lowercase()
403			);
404			
405			let mut seq = SequenceBuilder::new().start(A as u64).upper().build().unwrap();
406			for len in 1..5 {
407				assert_eq!(
408					seq.nth(26usize.pow(len as u32) - 1).unwrap().to_string(),
409					"A".repeat(len + 1),
410				);
411			}
412			
413			let mut seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
414			for len in 2..5 {
415				assert_eq!(
416					seq.nth(26usize.pow(len as u32) - 1).unwrap().to_string(),
417					"Z".repeat(len),
418				);
419			}
420		}
421	}
422
423}