Skip to content

Commit 9022c06

Browse files
committed
refactor: allow other Rust applications to use Dialect and its string serdes
1 parent 1d3f874 commit 9022c06

File tree

3 files changed

+74
-56
lines changed

3 files changed

+74
-56
lines changed

src/commands.rs

+2-28
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::validate::Dialect;
2+
13
pub struct ParameterInfo {
24
pub allow_plural: bool,
35
pub allow_gender: bool,
@@ -10,34 +12,6 @@ pub enum Occurence {
1012
EXACT, //< Command must match exactly with base.
1113
}
1214

13-
#[derive(PartialEq, Copy, Clone)]
14-
pub enum Dialect {
15-
NEWGRF,
16-
GAMESCRIPT,
17-
OPENTTD,
18-
}
19-
20-
impl From<&str> for Dialect {
21-
fn from(src: &str) -> Self {
22-
match src {
23-
"newgrf" => Dialect::NEWGRF,
24-
"game-script" => Dialect::GAMESCRIPT,
25-
"openttd" => Dialect::OPENTTD,
26-
_ => panic!(),
27-
}
28-
}
29-
}
30-
31-
impl Into<String> for Dialect {
32-
fn into(self) -> String {
33-
match self {
34-
Dialect::NEWGRF => String::from("newgrf"),
35-
Dialect::GAMESCRIPT => String::from("game-script"),
36-
Dialect::OPENTTD => String::from("openttd"),
37-
}
38-
}
39-
}
40-
4115
pub struct CommandInfo<'a> {
4216
pub name: &'a str,
4317
pub norm_name: Option<&'a str>,

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct Args {
2424
fn main() {
2525
let args = Args::parse();
2626
let config = validate::LanguageConfig {
27-
dialect: args.dialect,
27+
dialect: validate::Dialect::try_from(args.dialect.as_str()).unwrap(),
2828
cases: args.cases,
2929
genders: args.genders,
3030
plural_count: args.plural_count,

src/validate.rs

+71-27
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
use crate::commands::{CommandInfo, Dialect, Occurence, COMMANDS};
1+
use crate::commands::{CommandInfo, Occurence, COMMANDS};
22
use crate::parser::{FragmentContent, ParsedString};
33
use serde::{Deserialize, Serialize};
44
use std::collections::{BTreeMap, HashMap};
55

6+
#[derive(Debug, PartialEq, Copy, Clone)]
7+
pub enum Dialect {
8+
NEWGRF,
9+
GAMESCRIPT,
10+
OPENTTD,
11+
}
12+
613
#[derive(Deserialize, Debug)]
714
pub struct LanguageConfig {
8-
pub dialect: String, //< "newgrf", "game-script", "openttd"
15+
pub dialect: Dialect,
916
pub cases: Vec<String>,
1017
pub genders: Vec<String>,
1118
pub plural_count: usize,
@@ -32,20 +39,58 @@ pub struct ValidationResult {
3239
pub normalized: Option<String>,
3340
}
3441

35-
impl LanguageConfig {
36-
fn get_dialect(&self) -> Dialect {
37-
self.dialect.as_str().into()
38-
}
39-
42+
impl Dialect {
4043
pub fn allow_cases(&self) -> bool {
41-
self.get_dialect() != Dialect::GAMESCRIPT
44+
*self != Self::GAMESCRIPT
4245
}
4346

4447
fn allow_genders(&self) -> bool {
45-
self.get_dialect() != Dialect::GAMESCRIPT
48+
*self != Self::GAMESCRIPT
49+
}
50+
51+
fn as_str(&self) -> &'static str {
52+
match self {
53+
Self::NEWGRF => "newgrf",
54+
Self::GAMESCRIPT => "game-script",
55+
Self::OPENTTD => "openttd",
56+
}
4657
}
4758
}
4859

60+
impl TryFrom<&str> for Dialect {
61+
type Error = String;
62+
63+
fn try_from(value: &str) -> Result<Self, Self::Error> {
64+
match value {
65+
"newgrf" => Ok(Dialect::NEWGRF),
66+
"game-script" => Ok(Dialect::GAMESCRIPT),
67+
"openttd" => Ok(Dialect::OPENTTD),
68+
_ => Err(String::from("Unknown dialect")),
69+
}
70+
}
71+
}
72+
73+
impl<'de> Deserialize<'de> for Dialect {
74+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75+
where
76+
D: serde::Deserializer<'de>,
77+
{
78+
let string = String::deserialize(deserializer)?;
79+
let value = Dialect::try_from(string.as_str());
80+
value.map_err(|_| serde::de::Error::unknown_variant(string.as_str(), &["game-script", "newgrf", "openttd"]))
81+
}
82+
}
83+
84+
impl Serialize for Dialect {
85+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86+
where
87+
S: serde::Serializer,
88+
{
89+
serializer.serialize_str(self.as_str())
90+
}
91+
}
92+
93+
4994
impl Serialize for Severity {
5095
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
5196
where
@@ -90,7 +135,7 @@ pub fn validate_base(config: &LanguageConfig, base: &String) -> ValidationResult
90135
}
91136
} else {
92137
sanitize_whitespace(&mut base);
93-
normalize_string(&config.get_dialect(), &mut base);
138+
normalize_string(&config.dialect, &mut base);
94139
ValidationResult {
95140
errors: errs,
96141
normalized: Some(base.compile()),
@@ -130,7 +175,7 @@ pub fn validate_translation(
130175
Ok(parsed) => parsed,
131176
};
132177
if case != "default" {
133-
if !config.allow_cases() {
178+
if !config.dialect.allow_cases() {
134179
return ValidationResult {
135180
errors: vec![ValidationError {
136181
severity: Severity::Error,
@@ -177,7 +222,7 @@ pub fn validate_translation(
177222
}
178223
} else {
179224
sanitize_whitespace(&mut translation);
180-
normalize_string(&config.get_dialect(), &mut translation);
225+
normalize_string(&config.dialect, &mut translation);
181226
ValidationResult {
182227
errors: errs,
183228
normalized: Some(translation.compile()),
@@ -299,9 +344,8 @@ fn validate_string(
299344
test: &ParsedString,
300345
base: Option<&ParsedString>,
301346
) -> Vec<ValidationError> {
302-
let dialect = config.get_dialect();
303347
let signature: StringSignature;
304-
match get_signature(&dialect, base.unwrap_or(test)) {
348+
match get_signature(&config.dialect, base.unwrap_or(test)) {
305349
Ok(sig) => signature = sig,
306350
Err(msgs) => {
307351
if base.is_some() {
@@ -335,10 +379,10 @@ fn validate_string(
335379
.filter(|ex| ex.get_norm_name() == cmd.name)
336380
.or(COMMANDS
337381
.into_iter()
338-
.find(|ci| ci.name == cmd.name && ci.dialects.contains(&dialect)));
382+
.find(|ci| ci.name == cmd.name && ci.dialects.contains(&config.dialect)));
339383
if let Some(info) = opt_info {
340384
if let Some(c) = &cmd.case {
341-
if !config.allow_cases() {
385+
if !config.dialect.allow_cases() {
342386
errors.push(ValidationError {
343387
severity: Severity::Error,
344388
pos_begin: Some(fragment.pos_begin),
@@ -442,7 +486,7 @@ fn validate_string(
442486
front = 2;
443487
}
444488
FragmentContent::Gender(g) => {
445-
if !config.allow_genders() || config.genders.len() < 2 {
489+
if !config.dialect.allow_genders() || config.genders.len() < 2 {
446490
errors.push(ValidationError {
447491
severity: Severity::Error,
448492
pos_begin: Some(fragment.pos_begin),
@@ -497,7 +541,7 @@ fn validate_string(
497541
_ => panic!(),
498542
};
499543
let opt_ref_pos = cmd.indexref.or(opt_ref_pos);
500-
if cmd.name == "G" && (!config.allow_genders() || config.genders.len() < 2) {
544+
if cmd.name == "G" && (!config.dialect.allow_genders() || config.genders.len() < 2) {
501545
errors.push(ValidationError {
502546
severity: Severity::Error,
503547
pos_begin: Some(fragment.pos_begin),
@@ -881,7 +925,7 @@ mod tests {
881925
#[test]
882926
fn test_validate_empty() {
883927
let config = LanguageConfig {
884-
dialect: String::from("openttd"),
928+
dialect: Dialect::OPENTTD,
885929
cases: vec![],
886930
genders: vec![],
887931
plural_count: 0,
@@ -898,7 +942,7 @@ mod tests {
898942
#[test]
899943
fn test_validate_invalid() {
900944
let config = LanguageConfig {
901-
dialect: String::from("openttd"),
945+
dialect: Dialect::OPENTTD,
902946
cases: vec![],
903947
genders: vec![],
904948
plural_count: 0,
@@ -935,7 +979,7 @@ mod tests {
935979
#[test]
936980
fn test_validate_positional() {
937981
let config = LanguageConfig {
938-
dialect: String::from("openttd"),
982+
dialect: Dialect::OPENTTD,
939983
cases: vec![],
940984
genders: vec![],
941985
plural_count: 0,
@@ -1036,7 +1080,7 @@ mod tests {
10361080
#[test]
10371081
fn test_validate_front() {
10381082
let config = LanguageConfig {
1039-
dialect: String::from("openttd"),
1083+
dialect: Dialect::OPENTTD,
10401084
cases: vec![],
10411085
genders: vec![String::from("a"), String::from("b")],
10421086
plural_count: 0,
@@ -1119,7 +1163,7 @@ mod tests {
11191163
#[test]
11201164
fn test_validate_position_references() {
11211165
let config = LanguageConfig {
1122-
dialect: String::from("openttd"),
1166+
dialect: Dialect::OPENTTD,
11231167
cases: vec![String::from("x"), String::from("y")],
11241168
genders: vec![String::from("a"), String::from("b")],
11251169
plural_count: 2,
@@ -1293,7 +1337,7 @@ mod tests {
12931337
#[test]
12941338
fn test_validate_nochoices() {
12951339
let config = LanguageConfig {
1296-
dialect: String::from("openttd"),
1340+
dialect: Dialect::OPENTTD,
12971341
cases: vec![],
12981342
genders: vec![],
12991343
plural_count: 1,
@@ -1342,7 +1386,7 @@ mod tests {
13421386
#[test]
13431387
fn test_validate_gschoices() {
13441388
let config = LanguageConfig {
1345-
dialect: String::from("game-script"),
1389+
dialect: Dialect::GAMESCRIPT,
13461390
cases: vec![String::from("x"), String::from("y")],
13471391
genders: vec![String::from("a"), String::from("b")],
13481392
plural_count: 2,
@@ -1391,7 +1435,7 @@ mod tests {
13911435
#[test]
13921436
fn test_validate_choices() {
13931437
let config = LanguageConfig {
1394-
dialect: String::from("openttd"),
1438+
dialect: Dialect::OPENTTD,
13951439
cases: vec![String::from("x"), String::from("y")],
13961440
genders: vec![String::from("a"), String::from("b")],
13971441
plural_count: 2,
@@ -1455,7 +1499,7 @@ mod tests {
14551499
#[test]
14561500
fn test_validate_nonpositional() {
14571501
let config = LanguageConfig {
1458-
dialect: String::from("openttd"),
1502+
dialect: Dialect::OPENTTD,
14591503
cases: vec![],
14601504
genders: vec![],
14611505
plural_count: 0,

0 commit comments

Comments
 (0)