trl_codegen 1.2.1

This library provides auto generation of some common methods based on Rust macros
Documentation
//! # accessor_arg
//! This module contains the `AccessorArg` enum which represents a single argument of an attribute
//!

use crate::fields::FieldParam;
use crate::modifier::Modifier;
use syn::Token;
use syn::parse::discouraged::Speculative;
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::{Error, Expr, ExprArray, MetaNameValue, Result};

/// Enum AccessorArg represents a single argument of an accessor attribute
pub enum AccessorArg {
    /// Fields to include
    Includes(Vec<String>),
    /// Fields to exclude
    Excludes(Vec<String>),
    /// Prefix
    Prefix(String),
    /// Include public fields
    Pub,
    /// `self` modifier
    Modifier(Modifier),
    /// method (getter/setter) name
    Name(String),
    /// Process fields of type `Option`
    FieldParam(FieldParam),
}

impl AccessorArg {
    /// If the parsed value is MetaNameValue, this means its the construction like: name = value.
    /// This method parses this construction into an `Arg`
    pub fn nv_to_arg(nv: &MetaNameValue) -> Result<Self> {
        match nv
            .path
            .get_ident()
            .expect("Wrong name. Expected identifier")
            .to_string()
            .as_str()
        {
            "includes" => Ok(AccessorArg::Includes(AccessorArg::brackets_to_vec(
                &nv.value,
            )?)),
            "excludes" => Ok(AccessorArg::Excludes(AccessorArg::brackets_to_vec(
                &nv.value,
            )?)),
            "prefix" => Ok(AccessorArg::Prefix(AccessorArg::ident_to_string(
                &nv.value,
            )?)),
            "name" => Ok(AccessorArg::Name(AccessorArg::ident_to_string(&nv.value)?)),
            _ => Result::Err(Error::new(nv.span(), "Unknown arg name")),
        }
    }

    /// This method parses the `[...]` brackets expression into a vector
    pub fn brackets_to_vec(brackets: &Expr) -> Result<Vec<String>> {
        if let Expr::Array(ExprArray { elems, .. }) = brackets {
            let res = elems
                .iter()
                .map(|e| {
                    if let Expr::Path(path) = e {
                        path.path
                            .get_ident()
                            .expect("Could not parse value")
                            .to_string()
                    } else {
                        "".to_string()
                    }
                })
                .collect::<Vec<_>>();

            return Result::Ok(res);
        };

        Err(Error::new(
            brackets.span(),
            "Wrong expressing. Expected array",
        ))
    }

    /// This method parses the single identifier into string
    pub fn ident_to_string(expr: &Expr) -> Result<String> {
        if let Expr::Path(path) = expr {
            Ok(path.path.get_ident().expect("Expected ident").to_string())
        } else {
            Err(Error::new(
                expr.span(),
                "Could not parse arg value. Excpected ident",
            ))
        }
    }
}

impl Parse for AccessorArg {
    fn parse(input: ParseStream) -> Result<Self> {
        let start = input.fork();

        if let Ok(modifier) = start.parse::<Modifier>() {
            input.advance_to(&start);
            return Ok(AccessorArg::Modifier(modifier));
        }

        let start = input.fork();
        if let Ok(_) = start.parse::<Token![pub]>() {
            input.advance_to(&start);
            return Ok(AccessorArg::Pub);
        }

        let start = input.fork();
        if let Ok(nv) = start.parse::<MetaNameValue>() {
            input.advance_to(&start);
            return AccessorArg::nv_to_arg(&nv);
        }

        let start = input.fork();
        if let Ok(p) = start.parse::<FieldParam>() {
            input.advance_to(&start);
            return Ok(AccessorArg::FieldParam(p));
        }

        let msg = format!(
            "Expected one of: Modifier, `pub`, MetaNameValue, FieldParam, but got: {}",
            input.to_string()
        );
        Err(input.error(msg))
    }
}