diff --git a/vidyut-chandas/src/vrtta.rs b/vidyut-chandas/src/vrtta.rs index 41706ed..90301a2 100644 --- a/vidyut-chandas/src/vrtta.rs +++ b/vidyut-chandas/src/vrtta.rs @@ -74,36 +74,40 @@ impl Gana { } } -fn to_weights(text: &str) -> Vec { - text.chars() - .filter_map(|c| match c { - '.' => Some(PatternWeight::Any), - 'L' => Some(PatternWeight::L), - 'G' => Some(PatternWeight::G), - _ => None, - }) - .collect() -} - fn to_counts(text: &str) -> Vec { text.split_whitespace() .filter_map(|n| n.parse().ok()) .collect() } +/// Models a *pāda*, which is one of the four "feet" or "legs" of a verse. +/// A *pāda* defines a specific pattern of light and heavy syllables and +/// might also define one or more *yati*s (caesuras). +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Pada { + weights: Vec, + yati: Vec, +} + +impl Pada { + fn new(weights: Vec, yati: Vec) -> Self { + Pada { weights, yati } + } +} + /// Models a *vṛtta*, which defines a specific pattern of light and heavy syllables. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Vrtta { name: String, - weights: Vec>, + padas: Vec, } impl Vrtta { /// Creates a new `Vrtta` with the given name and weight pattern. - pub fn new(name: impl AsRef, weights: Vec>) -> Self { + pub fn new(name: impl AsRef, padas: Vec) -> Self { Self { name: name.as_ref().to_string(), - weights, + padas, } } @@ -115,8 +119,8 @@ impl Vrtta { } #[allow(unused)] - pub(crate) fn weights(&self) -> &Vec> { - &self.weights + pub(crate) fn padas(&self) -> &Vec { + &self.padas } pub(crate) fn try_match(&self, aksharas: &[Vec]) -> MatchType { @@ -133,9 +137,13 @@ impl Vrtta { eprintln!(); let mut full = Vec::new(); + while full.len() < 4 { - full.extend(self.weights.clone()); + for p in &self.padas { + full.push(p.weights.clone()); + } } + debug_assert_eq!(full.len(), 4); if let Some(last) = full[1].last_mut() { *last = Any; @@ -187,10 +195,11 @@ impl Vrtta { use PatternWeight::*; let mut result = Vec::new(); - for pada in &self.weights { + + for pada in &self.padas { let mut ganas = Vec::new(); - for chunk in pada.chunks(3) { + for chunk in pada.weights.chunks(3) { match chunk { [L, G, G] => ganas.push(Ya), [G, G, G] => ganas.push(Ma), @@ -217,6 +226,28 @@ impl Vrtta { } } +impl TryFrom<&str> for Pada { + type Error = Box; + + fn try_from(text: &str) -> Result { + let weights: Vec = text + .chars() + .filter_map(|c| match c { + '.' => Some(PatternWeight::Any), + 'L' => Some(PatternWeight::L), + 'G' => Some(PatternWeight::G), + _ => None, + }) + .collect(); + let yati: Vec = text + .match_indices('|') + .enumerate() + .map(|(i, (offset, _))| offset - i) + .collect(); + Ok(Pada::new(weights, yati)) + } +} + impl TryFrom<&str> for Vrtta { type Error = Box; @@ -227,8 +258,10 @@ impl TryFrom<&str> for Vrtta { let name = fields[0]; let _ = fields[1]; let pattern_str = fields[2]; - let weights = pattern_str.split("/").map(to_weights).collect(); - Ok(Vrtta::new(name, weights)) + let padas: Result, Box> = + pattern_str.split("/").map(|x| x.try_into()).collect(); + let padas = padas?; + Ok(Vrtta::new(name, padas)) } }