use super::{CodecTypePath, DecodeRefusal, PathRooting};
use crate::bounded::Overflow;
use crate::token::{
GeneratedDelimiter, GeneratedToken, absolute_path, bound_path, call, group, method_call, vector,
};
pub(super) const MATERIAL_BINDING: &str = "material";
pub(super) const REMAINING_BINDING: &str = "remaining";
pub(super) const INTO_BINDING: &str = "into";
pub(super) const NESTED_BINDING: &str = "nested";
pub(super) const COLLECTED_BINDING: &str = "collected";
pub(super) const CANDIDATE_BINDING: &str = "candidate";
pub(super) const CHOSEN_BINDING: &str = "chosen";
pub(super) const ELECTED_BINDING: &str = "elected";
pub(super) const PRESENT_BINDING: &str = "present";
pub(super) const CARRIED_BINDING: &str = "carried";
pub(super) const LENGTH_BINDING: &str = "length";
pub(super) const WIDTH_BINDING: &str = "width";
pub(super) const MEMBER_SEAT: &str = "member";
pub(super) fn associated(spelling: &str) -> Vec<GeneratedToken> {
vec![
GeneratedToken::joint(':'),
GeneratedToken::alone(':'),
GeneratedToken::word(spelling),
]
}
pub(super) fn statement(mut tokens: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
tokens.push(GeneratedToken::alone(';'));
tokens
}
pub(super) fn generics(arguments: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::alone('<')];
tokens.extend(arguments);
tokens.push(GeneratedToken::alone('>'));
tokens
}
pub(super) fn qualified(
subject: Vec<GeneratedToken>,
contract: Vec<GeneratedToken>,
road: &str,
) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::alone('<')];
tokens.extend(subject);
tokens.push(GeneratedToken::word("as"));
tokens.extend(contract);
tokens.push(GeneratedToken::alone('>'));
tokens.extend(associated(road));
tokens
}
pub(super) fn type_path(path: &CodecTypePath) -> Vec<GeneratedToken> {
let segments: Vec<&str> = path.segments().collect();
match path.rooting() {
PathRooting::CrateAbsolute => bound_path("crate", &segments),
PathRooting::SelfScoped => bound_path("self", &segments),
PathRooting::ParentScoped => bound_path("super", &segments),
PathRooting::InScope => match segments.split_first() {
Some((root, rest)) => bound_path(root, rest),
None => Vec::new(),
},
}
}
pub(super) fn bound_mutable(name: &str, expression: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
let mut tokens = vec![
GeneratedToken::word("let"),
GeneratedToken::word("mut"),
GeneratedToken::word(name),
GeneratedToken::alone('='),
];
tokens.extend(expression);
statement(tokens)
}
pub(super) fn reassigned(name: &str, expression: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::word(name), GeneratedToken::alone('=')];
tokens.extend(expression);
statement(tokens)
}
pub(super) fn framing_width() -> Vec<GeneratedToken> {
sized_width("u64")
}
pub(super) fn byte_width() -> Vec<GeneratedToken> {
sized_width("u8")
}
fn sized_width(name: &str) -> Vec<GeneratedToken> {
let mut tokens = absolute_path(&["core", "mem", "size_of"]);
tokens.push(GeneratedToken::joint(':'));
tokens.push(GeneratedToken::alone(':'));
tokens.extend(generics(vec![GeneratedToken::word(name)]));
tokens
}
pub(super) fn byte_sink() -> Vec<GeneratedToken> {
let mut tokens = absolute_path(&["std", "vec", "Vec"]);
tokens.extend(generics(vec![GeneratedToken::word("u8")]));
tokens
}
pub(super) fn byte_slice() -> Result<Vec<GeneratedToken>, Overflow> {
Ok(vec![group(
GeneratedDelimiter::Bracket,
vec![GeneratedToken::word("u8")],
)?])
}
pub(super) fn empty_vector() -> Result<Vec<GeneratedToken>, Overflow> {
vector(Vec::new())
}
pub(super) fn framed_length(
material: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
let counted = method_call(material, "len", Vec::new())?;
let mut narrowing = vec![GeneratedToken::word("u64")];
narrowing.extend(associated("try_from"));
let narrowed = call(narrowing, counted)?;
let mut ceiling = vec![GeneratedToken::word("u64")];
ceiling.extend(associated("MAX"));
let held = method_call(narrowed, "unwrap_or", ceiling)?;
let bytes = method_call(held, "to_be_bytes", Vec::new())?;
let mut tokens = vec![GeneratedToken::alone('&')];
tokens.extend(bytes);
Ok(tokens)
}
pub(super) fn appended(material: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
let called = method_call(
vec![GeneratedToken::word(INTO_BINDING)],
"extend_from_slice",
material,
)?;
Ok(statement(called))
}
pub(super) fn mapped(refusal: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
let mut closure = vec![
GeneratedToken::alone('|'),
GeneratedToken::word("_"),
GeneratedToken::alone('|'),
];
closure.extend(refusal);
let mut tokens = call(
vec![GeneratedToken::alone('.'), GeneratedToken::word("map_err")],
closure,
)?;
tokens.push(GeneratedToken::alone('?'));
Ok(tokens)
}
pub(super) fn absent(refusal: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = call(
vec![GeneratedToken::alone('.'), GeneratedToken::word("ok_or")],
refusal,
)?;
tokens.push(GeneratedToken::alone('?'));
Ok(tokens)
}
pub(super) fn sole_refusal(refusal: &str, arm: DecodeRefusal) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::word(refusal)];
tokens.extend(associated(arm.name()));
tokens
}
pub(super) fn member_refusal(
refusal: &str,
arm: DecodeRefusal,
member: &str,
) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = sole_refusal(refusal, arm);
tokens.push(group(
GeneratedDelimiter::Brace,
vec![
GeneratedToken::word(MEMBER_SEAT),
GeneratedToken::alone(':'),
GeneratedToken::text(member),
GeneratedToken::alone(','),
],
)?);
Ok(tokens)
}
pub(super) fn self_member(spelling: &str) -> Vec<GeneratedToken> {
vec![
GeneratedToken::word("self"),
GeneratedToken::alone('.'),
GeneratedToken::word(spelling),
]
}
pub(super) fn borrowed_self_member(spelling: &str) -> Result<Vec<GeneratedToken>, Overflow> {
let mut inner = vec![GeneratedToken::alone('&')];
inner.extend(self_member(spelling));
Ok(vec![group(GeneratedDelimiter::Parenthesis, inner)?])
}
pub(super) fn road_spelling(stated: &'static str) -> &'static str {
stated.rsplit("::").next().unwrap_or(stated)
}