hangman_solver_lib/language/
mod.rs1pub mod word_sequence;
4
5use std::num::NonZeroUsize;
6
7#[cfg(feature = "pyo3")]
8use std::ops::Div;
9
10#[cfg(feature = "pyo3")]
11use pyo3::create_exception;
12#[cfg(feature = "pyo3")]
13use pyo3::exceptions::PyValueError;
14#[cfg(feature = "pyo3")]
15use pyo3::prelude::*;
16
17pub use word_sequence::WordSequence;
18
19#[allow(unsafe_code)]
20#[cfg_attr(feature = "pyo3", pyclass)]
21pub struct StringChunkIter {
22 padded_word_byte_count: NonZeroUsize,
23 is_ascii: bool,
24 index: usize,
25 string: &'static str,
26}
27
28impl Iterator for StringChunkIter {
29 type Item = &'static str;
30
31 #[inline]
32 fn next(&mut self) -> Option<Self::Item> {
33 let end_index =
34 self.index.checked_add(self.padded_word_byte_count.get())?;
35 debug_assert_ne!(self.index, end_index);
36
37 let result = self.string.get(self.index..end_index)?;
38
39 let result = if self.is_ascii {
40 result
41 } else {
42 result.trim_start_matches('\0')
43 };
44
45 debug_assert!(end_index <= self.string.len());
46 self.index = end_index;
47 debug_assert!(!result.contains('\0'));
48 Some(result)
49 }
50}
51
52#[cfg(feature = "pyo3")]
53#[pymethods]
54impl StringChunkIter {
55 #[must_use]
56 const fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
57 slf
58 }
59
60 #[must_use]
61 fn __next__(&mut self) -> Option<&'static str> {
62 self.next()
63 }
64
65 #[must_use]
66 pub fn __len__(&self) -> usize {
67 self.string
68 .len()
69 .checked_sub(self.index)
70 .map_or(0, |rest| rest.div(self.padded_word_byte_count))
71 }
72}
73
74include!(concat!(env!("OUT_DIR"), "/language.rs"));
75
76#[cfg(feature = "pyo3")]
77create_exception!(hangman_solver, UnknownLanguageError, PyValueError);