ryo-source 0.1.0

High-speed Rust AST manipulation engine
Documentation
//! ToSyn implementations for items and use statements.

use syn::token;

use super::helpers::ident;
use super::{ToSyn, ToSynError};
use crate::pure::ast::{PureItem, PureUse, PureUseTree};

impl ToSyn for PureItem {
    type Output = syn::Item;

    fn to_syn(&self) -> Result<syn::Item, ToSynError> {
        Ok(match self {
            PureItem::Use(u) => syn::Item::Use(u.to_syn()?),
            PureItem::Fn(f) => syn::Item::Fn(f.to_syn()?),
            PureItem::Struct(s) => syn::Item::Struct(s.to_syn()?),
            PureItem::Enum(e) => syn::Item::Enum(e.to_syn()?),
            PureItem::Impl(i) => syn::Item::Impl(i.to_syn()?),
            PureItem::Const(c) => syn::Item::Const(c.to_syn()?),
            PureItem::Static(s) => syn::Item::Static(s.to_syn()?),
            PureItem::Type(t) => syn::Item::Type(t.to_syn()?),
            PureItem::Mod(m) => syn::Item::Mod(m.to_syn()?),
            PureItem::Trait(t) => syn::Item::Trait(t.to_syn()?),
            PureItem::Macro(m) => syn::Item::Macro(m.to_syn()?),
            PureItem::Other(s) => syn::parse_str(s).map_err(|e| ToSynError::Other {
                message: format!("Failed to parse item '{}': {}", s, e),
            })?,
        })
    }
}

impl ToSyn for PureUse {
    type Output = syn::ItemUse;

    fn to_syn(&self) -> Result<syn::ItemUse, ToSynError> {
        Ok(syn::ItemUse {
            attrs: vec![],
            vis: self.vis.to_syn()?,
            use_token: token::Use::default(),
            leading_colon: None,
            tree: self.tree.to_syn()?,
            semi_token: token::Semi::default(),
        })
    }
}

impl ToSyn for PureUseTree {
    type Output = syn::UseTree;

    fn to_syn(&self) -> Result<syn::UseTree, ToSynError> {
        Ok(match self {
            PureUseTree::Path { path, tree } => syn::UseTree::Path(syn::UsePath {
                ident: ident(path),
                colon2_token: token::PathSep::default(),
                tree: Box::new(tree.to_syn()?),
            }),
            PureUseTree::Name(name) => syn::UseTree::Name(syn::UseName { ident: ident(name) }),
            PureUseTree::Rename { name, rename } => syn::UseTree::Rename(syn::UseRename {
                ident: ident(name),
                as_token: token::As::default(),
                rename: ident(rename),
            }),
            PureUseTree::Glob => syn::UseTree::Glob(syn::UseGlob {
                star_token: token::Star::default(),
            }),
            PureUseTree::Group(items) => syn::UseTree::Group(syn::UseGroup {
                brace_token: token::Brace::default(),
                items: items.iter().map(|t| t.to_syn()).collect::<Result<_, _>>()?,
            }),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pure::ast::PureVis;
    use quote::ToTokens;

    #[test]
    fn test_pure_use_simple() {
        let use_stmt = PureUse {
            vis: PureVis::Private,
            tree: PureUseTree::Path {
                path: "std".to_string(),
                tree: Box::new(PureUseTree::Name("io".to_string())),
            },
        };
        let syn_use = use_stmt.to_syn().unwrap();
        let output = syn_use.to_token_stream().to_string();
        assert!(output.contains("std"), "Output: {}", output);
        assert!(output.contains("io"), "Output: {}", output);
    }

    #[test]
    fn test_pure_use_glob() {
        let use_stmt = PureUse {
            vis: PureVis::Public,
            tree: PureUseTree::Path {
                path: "std".to_string(),
                tree: Box::new(PureUseTree::Glob),
            },
        };
        let syn_use = use_stmt.to_syn().unwrap();
        let output = syn_use.to_token_stream().to_string();
        assert!(output.contains("pub"), "Output: {}", output);
        assert!(output.contains("*"), "Output: {}", output);
    }

    #[test]
    fn test_pure_use_group() {
        let use_stmt = PureUse {
            vis: PureVis::Private,
            tree: PureUseTree::Path {
                path: "std".to_string(),
                tree: Box::new(PureUseTree::Group(vec![
                    PureUseTree::Name("io".to_string()),
                    PureUseTree::Name("fs".to_string()),
                ])),
            },
        };
        let syn_use = use_stmt.to_syn().unwrap();
        let output = syn_use.to_token_stream().to_string();
        assert!(output.contains("io"), "Output: {}", output);
        assert!(output.contains("fs"), "Output: {}", output);
    }
}