php_codegen 0.4.0

Generate PHP code from Rust using a fluent API 🐘 🦀
Documentation
use crate::modifiers::VisibilityModifier;
use crate::Generator;
use crate::Indentation;

#[derive(Debug)]
pub struct Usage {
    pub traits: Vec<String>,
    pub adaptations: Vec<UsageAdaptation>,
}

#[derive(Debug)]
pub enum UsageAdaptation {
    Alias {
        method: String,
        alias: String,
        visibility: Option<VisibilityModifier>,
    },
    Visibility {
        method: String,
        visibility: VisibilityModifier,
    },
    Precedence {
        method: String,
        insteadof: Vec<String>,
    },
}

impl Usage {
    pub fn new(traits: Vec<String>) -> Self {
        Self {
            traits,
            adaptations: vec![],
        }
    }

    pub fn with<T: ToString>(mut self, r#trait: T) -> Self {
        self.traits.push(r#trait.to_string());

        self
    }

    pub fn alias<T: ToString>(
        mut self,
        method: T,
        alias: T,
        visibility: VisibilityModifier,
    ) -> Self {
        self.adaptations.push(UsageAdaptation::Alias {
            method: method.to_string(),
            alias: alias.to_string(),
            visibility: Some(visibility),
        });

        self
    }

    pub fn rename<T: ToString>(mut self, method: T, alias: T) -> Self {
        self.adaptations.push(UsageAdaptation::Alias {
            method: method.to_string(),
            alias: alias.to_string(),
            visibility: None,
        });

        self
    }

    pub fn public<T: ToString>(mut self, method: T) -> Self {
        self.adaptations.push(UsageAdaptation::Visibility {
            method: method.to_string(),
            visibility: VisibilityModifier::Public,
        });

        self
    }

    pub fn protected<T: ToString>(mut self, method: T) -> Self {
        self.adaptations.push(UsageAdaptation::Visibility {
            method: method.to_string(),
            visibility: VisibilityModifier::Protected,
        });

        self
    }

    pub fn private<T: ToString>(mut self, method: T) -> Self {
        self.adaptations.push(UsageAdaptation::Visibility {
            method: method.to_string(),
            visibility: VisibilityModifier::Private,
        });

        self
    }

    pub fn visibility<T: ToString>(mut self, method: T, visibility: VisibilityModifier) -> Self {
        self.adaptations.push(UsageAdaptation::Visibility {
            method: method.to_string(),
            visibility,
        });

        self
    }

    pub fn precede<T: ToString>(mut self, method: T, insteadof: Vec<T>) -> Self {
        self.adaptations.push(UsageAdaptation::Precedence {
            method: method.to_string(),
            insteadof: insteadof
                .into_iter()
                .map(|insteadof| insteadof.to_string())
                .collect(),
        });

        self
    }
}

impl Generator for Usage {
    fn generate(&self, indentation: Indentation, level: usize) -> String {
        let mut code = indentation.indent("use", level);

        code.push(' ');
        code.push_str(&self.traits.join(", "));

        if !self.adaptations.is_empty() {
            code.push_str(" {\n");
            for adaptation in &self.adaptations {
                let adaptation = match adaptation {
                    UsageAdaptation::Alias {
                        method,
                        alias,
                        visibility,
                    } => {
                        let alias = if let Some(visibility) = visibility {
                            format!("{} {}", visibility.generate(indentation, level), alias)
                        } else {
                            alias.to_string()
                        };

                        indentation.indent(format!("{} as {}", method, alias), level + 1)
                    }
                    UsageAdaptation::Visibility { method, visibility } => indentation.indent(
                        format!("{} as {}", method, visibility.generate(indentation, level)),
                        level + 1,
                    ),
                    UsageAdaptation::Precedence { method, insteadof } => indentation.indent(
                        format!("{} insteadof {}", method, insteadof.join(", ")),
                        level + 1,
                    ),
                };

                code.push_str(&format!("{};\n", adaptation));
            }

            code.push_str(&format!("{}}}\n", indentation.value(level)));
        } else {
            code.push_str(";\n");
        }

        code
    }
}

impl Generator for Vec<Usage> {
    fn generate(&self, indentation: Indentation, level: usize) -> String {
        let mut code = String::new();
        if self.is_empty() {
            return code;
        }

        for usage in self {
            code.push_str(usage.generate(indentation, level).as_str());
        }

        code.push('\n');

        code
    }
}

impl From<String> for Usage {
    fn from(r#trait: String) -> Self {
        Self::new(vec![r#trait])
    }
}

impl From<&str> for Usage {
    fn from(r#trait: &str) -> Self {
        Self::new(vec![r#trait.to_string()])
    }
}

impl<T: ToString> From<Vec<T>> for Usage {
    fn from(traits: Vec<T>) -> Self {
        traits
            .into_iter()
            .fold(Self::new(vec![]), |usage, r#trait| usage.with(r#trait))
    }
}