use {
proc_macro2::TokenStream,
quote::{quote_spanned, ToTokens},
std::{fmt, rc::Rc},
syn::{Path, Type},
};
use crate::Spanned;
#[derive(Clone, Debug)]
pub enum Target {
Done,
Recv(Type, Rc<Spanned<Target>>),
Send(Type, Rc<Spanned<Target>>),
Choose(Vec<Spanned<Target>>),
Offer(Vec<Spanned<Target>>),
Loop(Rc<Spanned<Target>>),
Continue(usize),
Split {
tx_only: Rc<Spanned<Target>>,
rx_only: Rc<Spanned<Target>>,
cont: Rc<Spanned<Target>>,
},
Call(Rc<Spanned<Target>>, Rc<Spanned<Target>>),
Then(Rc<Spanned<Target>>, Rc<Spanned<Target>>),
Type(Type),
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Target::*;
match self {
Done => write!(f, "Done")?,
Recv(t, s) => write!(f, "Recv<{}, {}>", t.to_token_stream(), s)?,
Send(t, s) => write!(f, "Send<{}, {}>", t.to_token_stream(), s)?,
Loop(s) => write!(f, "Loop<{}>", s)?,
Split {
tx_only: s,
rx_only: p,
cont: q,
} => write!(f, "Split<{}, {}, {}>", s, p, q)?,
Call(s, p) => write!(f, "Call<{}, {}>", s, p)?,
Then(s, p) => write!(f, "<{} as Then<{}>>::Combined", s, p)?,
Choose(cs) => {
let count = cs.len();
write!(f, "Choose<(")?;
for (i, c) in cs.iter().enumerate() {
write!(f, "{}", c)?;
if i + 1 < count {
write!(f, ", ")?;
}
}
if count == 1 {
write!(f, ",")?;
}
write!(f, ")>")?;
}
Offer(cs) => {
let count = cs.len();
write!(f, "Offer<(")?;
for (i, c) in cs.iter().enumerate() {
write!(f, "{}", c)?;
if i + 1 < count {
write!(f, ", ")?;
}
}
if count == 1 {
write!(f, ",")?;
}
write!(f, ")>")?;
}
Continue(n) => {
write!(f, "Continue<{}>", n)?;
}
Type(s) => write!(f, "{}", s.to_token_stream())?,
}
Ok(())
}
}
impl Spanned<Target> {
pub fn to_token_stream_with_crate_name(&self, dialectic_crate: &Path) -> TokenStream {
let mut tokens = TokenStream::new();
self.to_tokens_with_crate_name(dialectic_crate, &mut tokens);
tokens
}
pub fn to_tokens_with_crate_name(&self, dialectic_crate: &Path, tokens: &mut TokenStream) {
use Target::*;
let span = self.span;
match &self.inner {
Done => quote_spanned! {span=> #dialectic_crate::types::Done }.to_tokens(tokens),
Recv(t, s) => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> #dialectic_crate::types::Recv<#t, #s>).to_tokens(tokens);
}
Send(t, s) => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> #dialectic_crate::types::Send<#t, #s>).to_tokens(tokens);
}
Loop(s) => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> #dialectic_crate::types::Loop<#s>).to_tokens(tokens);
}
Split {
tx_only: s,
rx_only: p,
cont: q,
} => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
let p = p.to_token_stream_with_crate_name(dialectic_crate);
let q = q.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> #dialectic_crate::types::Split<#s, #p, #q>).to_tokens(tokens);
}
Call(s, p) => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
let p = p.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> #dialectic_crate::types::Call<#s, #p>).to_tokens(tokens);
}
Then(s, p) => {
let s = s.to_token_stream_with_crate_name(dialectic_crate);
let p = p.to_token_stream_with_crate_name(dialectic_crate);
quote_spanned!(span=> <#s as #dialectic_crate::types::Then<#p>>::Combined)
.to_tokens(tokens);
}
Choose(cs) => {
let cs = cs
.iter()
.map(|c| c.to_token_stream_with_crate_name(dialectic_crate));
quote_spanned!(span=> #dialectic_crate::types::Choose<(#(#cs,)*)>).to_tokens(tokens)
}
Offer(cs) => {
let cs = cs
.iter()
.map(|c| c.to_token_stream_with_crate_name(dialectic_crate));
quote_spanned!(span=> #dialectic_crate::types::Offer<(#(#cs,)*)>).to_tokens(tokens)
}
Continue(n) => {
quote_spanned!(span=> #dialectic_crate::types::Continue<#n>).to_tokens(tokens)
}
Type(s) => quote_spanned!(span=> #s).to_tokens(tokens),
}
}
}
impl ToTokens for Spanned<Target> {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.to_tokens_with_crate_name(&crate::dialectic_path(), tokens);
}
}