Skip to content

Commit

Permalink
Changed LazyLock to OnceLock
Browse files Browse the repository at this point in the history
* Made the switch for MSRV compatibility
  • Loading branch information
Vikram Bhaskaran committed Jan 19, 2025
1 parent 6771558 commit d1f8f43
Show file tree
Hide file tree
Showing 16 changed files with 271 additions and 173 deletions.
17 changes: 9 additions & 8 deletions vidyut-chandas/src/sounds.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::sync::LazyLock;
use std::sync::OnceLock;

static HRASVA: LazyLock<Set> = LazyLock::new(|| Set::from("aiufx"));
static AC: LazyLock<Set> = LazyLock::new(|| Set::from("aAiIuUfFxXeEoO"));
static HAL: LazyLock<Set> = LazyLock::new(|| Set::from("kKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL"));
static HRASVA: OnceLock<Set> = OnceLock::new();
static AC: OnceLock<Set> = OnceLock::new();
static HAL: OnceLock<Set> = OnceLock::new();

type Sound = char;

Expand Down Expand Up @@ -35,22 +35,23 @@ impl Set {

/// Returns whether `c` is a vowel.
pub(crate) fn is_ac(c: Sound) -> bool {
AC.contains(c)
AC.get_or_init(|| Set::from("aAiIuUfFxXeEoO")).contains(c)
}

/// Returns whether `c` is a short vowel.
pub(crate) fn is_hrasva(c: Sound) -> bool {
HRASVA.contains(c)
HRASVA.get_or_init(|| Set::from("aiufx")).contains(c)
}

/// Returns whether `c` is a consonant.
pub(crate) fn is_hal(c: Sound) -> bool {
HAL.contains(c)
HAL.get_or_init(|| Set::from("kKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL"))
.contains(c)
}

/// Returns whether `c` is a Sanskrit sound.
pub(crate) fn is_sanskrit(c: Sound) -> bool {
AC.contains(c) || HAL.contains(c) || matches!(c, 'M' | 'H')
is_ac(c) || is_hal(c) || matches!(c, 'M' | 'H')
}

/// Returns whether `s` starts with a consonant cluster.
Expand Down
10 changes: 6 additions & 4 deletions vidyut-cheda/src/normalize_text.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::LazyLock;
use std::sync::OnceLock;

use regex::Regex;

Expand All @@ -9,10 +9,12 @@ use regex::Regex;
/// 2. Delete all whitespace spans.
/// 3. Separate all remaining spans with a single " ".
pub fn normalize(text: &str) -> String {
static RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"([a-zA-Z']+)|(\s+)|([^a-zA-Z']+)").expect("always defined"));
static RE: OnceLock<Regex> = OnceLock::new();

let mut ret = RE
let re =
RE.get_or_init(|| Regex::new(r"([a-zA-Z']+)|(\s+)|([^a-zA-Z']+)").expect("always defined"));

let mut ret = re
.find_iter(text)
.map(|m| m.as_str())
.filter(|s| !s.trim().is_empty())
Expand Down
28 changes: 16 additions & 12 deletions vidyut-cheda/src/sounds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Utility functions for checking Sanskrit sounds.
use std::sync::LazyLock;
use std::sync::OnceLock;

/// A set of Sanskrit sounds.
///
Expand Down Expand Up @@ -42,35 +42,39 @@ impl Default for SoundSet {
/// - other punctuation characters (|, ||, numbers)
/// - characters or symbols from non-SLP1 encodings
pub fn is_sanskrit(c: char) -> bool {
static CHARS: LazyLock<SoundSet> =
LazyLock::new(|| SoundSet::from("aAiIuUfFxXeEoOMHkKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL'"));
CHARS.contains(c)
static CHARS: OnceLock<SoundSet> = OnceLock::new();
let chars =
CHARS.get_or_init(|| SoundSet::from("aAiIuUfFxXeEoOMHkKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL'"));
chars.contains(c)
}

/// Returns whether the given sound is a vowel.
///
/// `ac` is the Paninian name for the Sanskrit vowels.
pub fn is_ac(c: char) -> bool {
static AC: LazyLock<SoundSet> = LazyLock::new(|| SoundSet::from("aAiIuUfFxXeEoO"));
AC.contains(c)
static AC: OnceLock<SoundSet> = OnceLock::new();
let ac = AC.get_or_init(|| SoundSet::from("aAiIuUfFxXeEoO"));
ac.contains(c)
}

/// Returns whether the given sound is a consonant.
///
/// `hal` is the Paninian name for the Sanskrit consonants.
#[allow(unused)]
pub fn is_hal(c: char) -> bool {
static HAL: LazyLock<SoundSet> =
LazyLock::new(|| SoundSet::from("kKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL"));
HAL.contains(c)
static HAL: OnceLock<SoundSet> = OnceLock::new();

let hal = HAL.get_or_init(|| SoundSet::from("kKgGNcCjJYwWqQRtTdDnpPbBmyrlvSzshL"));
hal.contains(c)
}

/// Returns whether the given sound is voiced.
#[allow(unused)]
pub fn is_ghosha(c: char) -> bool {
static GHOSHA: LazyLock<SoundSet> =
LazyLock::new(|| SoundSet::from("aAiIuUfFxXeEoOgGNjJYqQRdDnbBmyrlvh"));
GHOSHA.contains(c)
static GHOSHA: OnceLock<SoundSet> = OnceLock::new();

let ghosha = GHOSHA.get_or_init(|| SoundSet::from("aAiIuUfFxXeEoOgGNjJYqQRdDnbBmyrlvh"));
ghosha.contains(c)
}

#[cfg(test)]
Expand Down
21 changes: 21 additions & 0 deletions vidyut-prakriya/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ our system.
This document assumes some familiarity with basic Rust concepts like structs,
enums, closures, and lifetimes.


Goals and values
----------------

Expand Down Expand Up @@ -39,6 +40,7 @@ than wait for perfect clarity. Fortunately, we have found that as the program
has grown and matured, we have become more and more able to remove hacks and
solve problems in a more fundamental way.


Core data types
---------------

Expand All @@ -64,18 +66,21 @@ In addition to these three types, we recommend exploring the types in the
part of its API. Our hope is that callers can lean on Rust's type system to
define meaningful requests and receive correct derivations.


Core modules
------------

We start our description here with the high-level `vyakarana` module then work
our way into specific implementation details.


### `vyakarana`

This defines the public API. Given certain input conditions, the method here
return all `Prakriya`s compatible with those conditions. `vyakarana` is a thin
wrapper over the `ashtadhyayi` module, which we describe below.


### `args`

This defines the argument types that `Vyakarana` accepts. The types here follow
Expand All @@ -84,6 +89,8 @@ Paninian categories as closely as possible, so we have types like `Dhatu`,
arguments are well formed. For example, a `Krdanta` must have a `Dhatu` and a
`Krt`.



### `ashtadhyayi`

This defines the core rules of the Ashtadhayi. Given the input constraints
Expand Down Expand Up @@ -111,6 +118,7 @@ their own modules. Some examples:
- `unadipatha`, which defines the rules of the Unadipatha. These rules enter
the Ashtadhyayi through rule 3.3.1 (*uṇādayo bahulam*)


### `prakriya`, `terms`, and `tags`

These define the `Prakriya` and `Term` types, as well as some useful secondary
Expand All @@ -122,18 +130,21 @@ variety of ad-hoc flags.

Since `Term` and `Tag` are not stable, we do not expose them in our public API.


### `prakriya_stack`

This module defines utilities for exploring different paths of optional rules.
The core type here is `PrakriyaStack`, which manages a stack of rule paths.
(`RulePathStack` might be a clearer name, but it doesn't quite roll off the
tongue!)


### `sounds`

This defines various functions for testing and modifying Sanskrit sounds. The
core data structure here is `Set`, which stores sounds in a simple array.


Code style
----------

Expand All @@ -154,6 +165,7 @@ the logic of each rule more obvious. Here, `p` is a `Prakriya`, `i` is the
index of some `Term` within the `Prakriya`, and `|t| ...` is a closure (inline
function) that accepts a `Term`.


### Closures

`run_at`, like many of the methods on `Prakriya`, accepts a closure.
Expand All @@ -176,6 +188,7 @@ for `p.terms[i]`. `Prakriya` also defines many methods for working with
indices, such as `find_first_where`, `find_last_where`, `find_next_where`,
and so on.


### Naming conventions

Since we have so many rules to write, we use short variable names for common
Expand All @@ -190,6 +203,7 @@ concepts. Some examples:
[rust-borrow]: https://users.rust-lang.org/t/newbie-mut-with-nested-structs/84755
[rust-q]: https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html


Control flow
------------

Expand All @@ -212,6 +226,7 @@ directly encodes a critical principle of the grammar.
The sections below extend the example above and illustrate the various kinds of
control flow we use, ordered from least to most complex.


### Rule sequences

The control flow in the example above is appropriate for simple sequences of
Expand All @@ -226,6 +241,7 @@ if condition_2 {
}
```


### Simple rule blocking

A natural extension is to use `if`-`else` chains to enforce that only one rule
Expand All @@ -241,6 +257,7 @@ if condition_1 {
}
```


### Falling through

If a rule is optional, we might wish to "fall through" and consider other
Expand All @@ -260,6 +277,7 @@ if condition_2 {

Here, `rule_2` is accessible even if we reject `rule_1`.


### Simple locking

If we fall through in a simple way, we could end up running both `rule_1` and
Expand All @@ -282,6 +300,7 @@ if done {
}
```


### Extended locking

Sometimes, we might wish to implement rule locking over a very large section of
Expand Down Expand Up @@ -326,10 +345,12 @@ If we use the new `do_something_1` and `do_something_2` methods here,
the original `Prakriya` struct, we can access it through `lp.p`. Once the
lifetime of `lp` has ended, we can continue using `p` as before.


### Context-aware locking

Suppose we wish to derive a *taddhitānta* that uses a specific
taddhita-pratyaya only if available in a specific meaning context. In this
case, we can extend the `LockingPrakriya` pattern above to record other useful
metadata, such as the meaning condition we wish to derive (if any). For
examples of this pattern, see `KrtPrakriya` and `TaddhitaPrakriya`.

9 changes: 6 additions & 3 deletions vidyut-prakriya/src/angasya/abhyasasya.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ abhyasasya
Runs rules that modify the abhyāsa.
*/

use std::sync::LazyLock;
use std::sync::OnceLock;

use crate::args::Agama as A;
use crate::args::Agama;
Expand Down Expand Up @@ -34,7 +34,7 @@ const KHAY: Set = s(&["Kay"]);
const F_HAL: Set = s(&["f hal"]);
const PU_YAN_J: Set = s(&["pu~", "yaR", "j"]);

static KUH_CU: LazyLock<Map> = LazyLock::new(|| map("ku~ h", "cu~"));
static KUH_CU: OnceLock<Map> = OnceLock::new();

/// Simplifies the abhyasa per 7.4.60.
fn try_haladi(text: &str) -> TermString {
Expand Down Expand Up @@ -268,7 +268,10 @@ fn try_general_rules(p: &mut Prakriya, i: usize) -> Option<()> {

let abhyasa = p.get(i)?;
let dhatu = p.get(i_dhatu)?;
if let Some(val) = KUH_CU.get(abhyasa.adi()?) {
if let Some(val) = KUH_CU
.get_or_init(|| map("ku~ h", "cu~"))
.get(abhyasa.adi()?)
{
let n = p.get(i_dhatu + 1)?;
if dhatu.has_u("ku\\N") && dhatu.has_gana(Gana::Bhvadi) && n.is(S::yaN) {
p.step("7.4.63");
Expand Down
6 changes: 3 additions & 3 deletions vidyut-prakriya/src/krt/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ use crate::krt::utils::KrtPrakriya;
use crate::sounds::{s, Set, AC, HAL, IK};
use crate::stem_gana::TYAD_ADI;
use crate::Rule::Varttika;
use std::sync::LazyLock;
use std::sync::OnceLock;

const II: Set = s(&["i"]);
const UU: Set = s(&["u"]);
const PU: Set = s(&["pu~"]);

static EMPTY_TERM: LazyLock<Term> = LazyLock::new(|| Term::make_text(""));
static EMPTY_TERM: OnceLock<Term> = OnceLock::new();

/// Tries to add various pratyayas that are just "a."
fn try_add_various_pratyayas(kp: &mut KrtPrakriya) {
Expand Down Expand Up @@ -561,7 +561,7 @@ fn try_add_upapada_krt(kp: &mut KrtPrakriya) -> Option<bool> {

let upapada = match kp.p.get_if(0, |t| t.has_tag(T::Pratipadika)) {
Some(t) => t,
None => &EMPTY_TERM,
None => &EMPTY_TERM.get_or_init(|| Term::make_text("")),
};
let upapade = kp.p.has(0, |t| t.has_tag(T::Pratipadika));

Expand Down
9 changes: 5 additions & 4 deletions vidyut-prakriya/src/sounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ We chose SLP1 over something like [WX][wx] merely because we have more familiari
[wx]: https://en.wikipedia.org/wiki/WX_notation
*/
use rustc_hash::FxHashMap;
use std::{fmt, sync::LazyLock};
use std::{fmt, sync::OnceLock};

type Sound = char;

Expand All @@ -48,7 +48,7 @@ pub const HAL: Set = s(&["hal"]);
pub const YAN: Set = s(&["yaR"]);
pub const VAL: Set = s(&["val"]);

static SOUND_PROPS: LazyLock<FxHashMap<Sound, Uccarana>> = LazyLock::new(create_sound_props);
static SOUND_PROPS: OnceLock<FxHashMap<Sound, Uccarana>> = OnceLock::new();

/// A set of Sanskrit sounds.
///
Expand Down Expand Up @@ -633,17 +633,18 @@ pub const fn savarna(c: Sound) -> Set {
pub(crate) fn map(keys: &str, values: &str) -> Map {
let keys = s_old(keys);
let values = s_old(values);
let sound_props = SOUND_PROPS.get_or_init(|| create_sound_props());

let mut map = Map::new();
for key in keys.to_string().chars() {
let key_props = SOUND_PROPS.get(&key).expect("called statically");
let key_props = sound_props.get(&key).expect("called statically");

// The best sound has the minimal distance.
let best_value = values
.to_string()
.chars()
.min_by_key(|v| {
SOUND_PROPS
sound_props
.get(v)
.expect("called statically")
.distance(key_props)
Expand Down
Loading

0 comments on commit d1f8f43

Please sign in to comment.