use proc_macro::{Delimiter, Span, TokenTree, token_stream};
use crate::{
cold,
metadata::{Channels, Depth, DepthChannels},
};
pub(crate) fn get_depth_channels(
caller: &'static str,
input: &mut token_stream::IntoIter,
) -> DepthChannels {
match input.next() {
Some(TokenTree::Group(grp)) if grp.delimiter() == Delimiter::Bracket => {
let mut iter = grp.stream().into_iter();
let depth = match iter.next() {
Some(TokenTree::Ident(ident)) => match &*ident.to_string() {
"bool" => Depth::One,
"u8" => Depth::Eight,
"u16" => Depth::Sixteen,
_ => cold::expected_token(caller, "bit depth type", ident.span()),
},
Some(other) => cold::expected_token(caller, "bit depth type", other.span()),
None => cold::expected_token(caller, "bit depth type", grp.span_close().start()),
};
match iter.next() {
Some(TokenTree::Punct(punct)) if punct.as_char() == ';' => (),
Some(other) => cold::expected_token(caller, "semicolon", other.span()),
None => cold::expected_token(caller, "semicolon", Span::call_site().end()),
}
let channels = match iter.next() {
Some(TokenTree::Literal(lit)) => match lit.to_string().parse::<u8>() {
Ok(1) => Channels::One,
Ok(2) => Channels::Two,
Ok(3) => Channels::Three,
Ok(4) => Channels::Four,
_ => cold::expected_token(caller, "channel count", lit.span()),
},
Some(other) => cold::expected_token(caller, "channel count", other.span()),
None => cold::expected_token(caller, "channel count", Span::call_site().end()),
};
if let Some(token) = iter.next() {
cold::extraneous_token(caller, token.span());
}
DepthChannels::new(depth, channels)
.expect("cannot have more than two channels for black-and-white image")
}
Some(other) => cold::expected_token(caller, "pixel format", other.span()),
None => cold::expected_token(caller, "pixel format", Span::call_site().end()),
}
}
pub(crate) struct LeadingComma;
pub(crate) fn get_file(
caller: &'static str,
input: &mut token_stream::IntoIter,
mut leading_comma: Option<LeadingComma>,
) -> String {
let lit = loop {
match input.next() {
Some(TokenTree::Literal(lit)) => break lit,
Some(TokenTree::Punct(punct))
if punct.as_char() == ',' && leading_comma.take().is_some() =>
{
continue;
}
Some(other) => cold::expected_token(caller, "filename", other.span()),
None => cold::expected_token(caller, "filename", Span::call_site()),
}
};
match input.next() {
Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
if let Some(other) = input.next() {
cold::extraneous_token(caller, other.span());
}
}
Some(other) => cold::extraneous_token(caller, other.span()),
None => (),
}
let span = lit.span();
let mut lit = lit.to_string();
assert!(
lit.starts_with("\"") && lit.ends_with("\"") && !lit.contains("\\"),
"unsupported string literal type at {span:?}"
);
lit.remove(0);
lit.pop();
lit
}