fn should_preserve_double_bang(tag_raw: &str) -> bool {
if let Some(suffix) = tag_raw.strip_prefix("!!") {
match suffix {
"str" | "int" | "float" | "bool" | "null" | "timestamp" | "yaml" | "binary" | "map"
| "seq" | "set" | "omap" | "pairs" => true,
"int:hex" | "int:oct" => true,
_ => false,
}
} else {
false
}
}
#[inline]
fn pick_tag_text(tag_raw: &str, resolved: String) -> String {
if tag_raw.starts_with("!!") {
if should_preserve_double_bang(tag_raw) {
tag_raw.to_owned()
} else {
resolved
}
} else {
tag_raw.to_owned()
}
}
fn try_coerce_tag(tag: &str, node: Node) -> Option<Node> {
match tag {
"!!int:hex" => match node {
Node::Str(s, _, _) => {
if let Some(stripped) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
if let Ok(i) = i64::from_str_radix(stripped, 16) {
Some(Node::Number(Numeric::Integer(i)))
} else {
None
}
} else {
None
}
}
_ => None,
},
"!!int:oct" => match node {
Node::Str(s, _, _) => {
if let Some(stripped) = s.strip_prefix("0o").or_else(|| s.strip_prefix("0O")) {
if let Ok(i) = i64::from_str_radix(stripped, 8) {
Some(Node::Number(Numeric::Integer(i)))
} else {
None
}
} else {
None
}
}
_ => None,
},
"!!str" | "!str" | "tag:yaml.org,2002:str" => {
let s = match node {
Node::Str(s, _, _) => s,
Node::Number(Numeric::Integer(i)) => i.to_string(),
Node::Number(Numeric::Float(f)) => f.to_string(),
Node::Boolean(b) => b.to_string(),
Node::None => String::new(),
_ => return None,
};
Some(Node::Str(s, QuoteType::Unquoted, BlockStyle::None))
}
"!!int" | "!int" | "tag:yaml.org,2002:int" => match node {
Node::Number(Numeric::Integer(i)) => Some(Node::Number(Numeric::Integer(i))),
Node::Str(s, _, _) => {
if let Ok(i) = s.parse::<i64>() {
Some(Node::Number(Numeric::Integer(i)))
} else if let Ok(f) = s.parse::<f64>() {
if f.fract() == 0.0 {
Some(Node::Number(Numeric::Integer(f as i64)))
} else {
None
}
} else {
None
}
}
Node::Number(Numeric::Float(f)) => {
if f.fract() == 0.0 {
Some(Node::Number(Numeric::Integer(f as i64)))
} else {
None
}
}
_ => None,
},
"!!float" | "!float" | "tag:yaml.org,2002:float" => match node {
Node::Number(Numeric::Float(f)) => Some(Node::Number(Numeric::Float(f))),
Node::Number(Numeric::Integer(i)) => Some(Node::Number(Numeric::Float(i as f64))),
Node::Str(s, _, _) => {
if let Ok(f) = s.parse::<f64>() {
Some(Node::Number(Numeric::Float(f)))
} else {
None
}
}
_ => None,
},
"!!bool" | "!bool" | "tag:yaml.org,2002:bool" => match node {
Node::Boolean(b) => Some(Node::Boolean(b)),
Node::Str(s, _, _) => {
let sl = s.trim().to_ascii_lowercase();
match sl.as_str() {
"true" | "yes" | "on" => Some(Node::Boolean(true)),
"false" | "no" | "off" => Some(Node::Boolean(false)),
_ => None,
}
}
Node::Number(Numeric::Integer(i)) => Some(Node::Boolean(i != 0)),
Node::Number(Numeric::Float(f)) => Some(Node::Boolean(f != 0.0)),
_ => None,
},
"!!set" | "!set" | "tag:yaml.org,2002:set" => match node {
Node::Mapping(pairs) => {
if let Some(set_items) =
crate::parser::utils::node_utils::pairs_to_set_items_if_all_none(&pairs)
{
Some(Node::Set(set_items))
} else {
None
}
}
Node::Array(items) => {
let mut unique_items = Vec::new();
for item in items {
if !unique_items.contains(&item) {
unique_items.push(item);
}
}
Some(Node::Set(unique_items))
}
Node::Set(items) => {
let mut flat = Vec::new();
for item in items {
match item {
Node::Set(nested) => flat.extend(nested),
other => flat.push(other),
}
}
Some(Node::Set(flat))
}
_ => Some(Node::Set(vec![node])),
},
"!!omap" | "!omap" | "tag:yaml.org,2002:omap" => match node {
Node::Array(items) => {
for item in &items {
match item {
Node::Mapping(pairs) if pairs.len() == 1 => {}
_ => return None, }
}
Some(Node::Tagged(
Box::new(Node::Array(items)),
"tag:yaml.org,2002:omap".to_string(),
))
}
_ => None,
},
"!!pairs" | "!pairs" | "tag:yaml.org,2002:pairs" => match node {
Node::Array(items) => Some(Node::Tagged(
Box::new(Node::Array(items)),
"tag:yaml.org,2002:pairs".to_string(),
)),
_ => None,
},
"!!null" | "!null" | "tag:yaml.org,2002:null" => Some(Node::None),
"!!timestamp" | "!timestamp" | "tag:yaml.org,2002:timestamp" => match node {
Node::Str(s, _, _) => Some(Node::Str(s, QuoteType::Unquoted, BlockStyle::None)),
Node::Number(Numeric::Integer(i)) => Some(Node::Str(
i.to_string(),
QuoteType::Unquoted,
BlockStyle::None,
)),
Node::Number(Numeric::Float(f)) => Some(Node::Str(
f.to_string(),
QuoteType::Unquoted,
BlockStyle::None,
)),
Node::Boolean(b) => Some(Node::Str(
b.to_string(),
QuoteType::Unquoted,
BlockStyle::None,
)),
Node::None => Some(Node::Str(
String::new(),
QuoteType::Unquoted,
BlockStyle::None,
)),
_ => None,
},
_ => None,
}
}