1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::parser::command::{
argument::{
brigadier::{expect, parse_possibly_quoted_string},
minecraft::nbt::CompoundNbt,
},
resource_location::ResourceLocationRef,
};
use ::nbt::Map;
use std::collections::BTreeMap;
#[derive(Clone, Debug, PartialEq)]
pub struct MinecraftBlockPredicate<'l> {
tag: bool,
block: ResourceLocationRef<&'l str>,
properties: BTreeMap<&'l str, &'l str>,
nbt: CompoundNbt,
}
impl<'l> MinecraftBlockPredicate<'l> {
pub fn parse(string: &'l str) -> Result<(Self, usize), String> {
let suffix = string;
let tag = string.starts_with('#');
let tag_len = if tag { '#'.len_utf8() } else { 0 };
let suffix = &suffix[tag_len..];
let (block, block_len) = ResourceLocationRef::parse(suffix)?;
let suffix = &suffix[block_len..];
let (properties, properties_len) = parse_properties(suffix)?;
let suffix = &suffix[properties_len..];
let (nbt, nbt_len) = parse_nbt(suffix)?;
Ok((
MinecraftBlockPredicate {
tag,
block,
properties,
nbt,
},
tag_len + block_len + properties_len + nbt_len,
))
}
}
fn parse_properties(string: &str) -> Result<(BTreeMap<&str, &str>, usize), String> {
let mut properties = BTreeMap::new();
let mut suffix = string;
if let Some(s) = string.strip_prefix('[') {
suffix = s.trim_start();
while !suffix.starts_with(']') {
let (key, len) = parse_possibly_quoted_string(suffix)?;
suffix = &suffix[len..].trim_start();
suffix = expect(suffix, '=')?.trim_start();
let (value, len) = parse_possibly_quoted_string(suffix)?;
suffix = &suffix[len..].trim_start();
properties.insert(key, value);
if let Some(s) = suffix.strip_prefix(',') {
suffix = s.trim_start();
} else {
break;
}
}
suffix = expect(suffix, ']')?;
}
Ok((properties, string.len() - suffix.len()))
}
fn parse_nbt(string: &str) -> Result<(CompoundNbt, usize), String> {
if string.starts_with('{') {
CompoundNbt::parse(string)
} else {
Ok((CompoundNbt(Map::new()), 0))
}
}