php_codegen 0.4.0

Generate PHP code from Rust using a fluent API 🐘 🦀
Documentation
use std::fmt::Debug;

use crate::Generator;
use crate::Indentation;

pub struct Body {
    pub factory: Option<Box<dyn Fn(Indentation, usize) -> String>>,
    pub semicolon_for_empty: bool,
}

impl Body {
    pub fn new() -> Self {
        Self {
            factory: None,
            semicolon_for_empty: true,
        }
    }

    pub fn with_factory<T: Fn(Indentation, usize) -> String + 'static>(factory: T) -> Self {
        Self {
            factory: Some(Box::new(factory)),
            semicolon_for_empty: true,
        }
    }

    pub fn with_semicolon_for_empty(mut self, semicolon_for_empty: bool) -> Self {
        self.semicolon_for_empty = semicolon_for_empty;

        self
    }
}

impl Debug for Body {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Body")
            .field("factory:is-some", &self.factory.is_some())
            .field("semicolon_for_empty", &self.semicolon_for_empty)
            .finish()
    }
}

impl Generator for Body {
    fn generate(&self, indentation: Indentation, level: usize) -> String {
        match self.factory {
            Some(ref factory) => {
                let mut code = String::new();

                code.push_str(" {");
                code.push('\n');
                code.push_str(&factory(indentation, level + 1));
                code.push('\n');
                code.push_str(&indentation.indent("}", level));
                code.push('\n');

                code
            }
            None => {
                let mut code = String::new();

                if self.semicolon_for_empty {
                    code.push(';');
                } else {
                    code.push_str(" {}");
                }

                code.push('\n');

                code
            }
        }
    }
}

impl<T: ToString> From<Vec<T>> for Body {
    fn from(body: Vec<T>) -> Self {
        let body = body
            .iter()
            .map(|line| line.to_string())
            .collect::<Vec<String>>();

        Self {
            factory: Some(Box::new(move |indentation, level| {
                let body = body.clone();

                body.iter()
                    .map(|line| indentation.indent(line.to_string(), level))
                    .collect::<Vec<String>>()
                    .join("\n")
            })),
            semicolon_for_empty: true,
        }
    }
}

impl From<String> for Body {
    fn from(body: String) -> Self {
        Self {
            factory: Some(Box::new(move |indentation, level| {
                let body = body.clone();

                indentation.indent(body, level)
            })),
            semicolon_for_empty: true,
        }
    }
}

impl From<&str> for Body {
    fn from(body: &str) -> Self {
        body.to_string().into()
    }
}

impl<T: Fn(Indentation, usize) -> String + 'static> From<T> for Body {
    fn from(factory: T) -> Self {
        Self {
            factory: Some(Box::new(factory)),
            semicolon_for_empty: true,
        }
    }
}

impl From<Option<Box<dyn Fn(Indentation, usize) -> String>>> for Body {
    fn from(factory: Option<Box<dyn Fn(Indentation, usize) -> String>>) -> Self {
        Self {
            factory,
            semicolon_for_empty: true,
        }
    }
}

impl From<Option<String>> for Body {
    fn from(body: Option<String>) -> Self {
        match body {
            Some(body) => body.into(),
            None => Self {
                factory: None,
                semicolon_for_empty: true,
            },
        }
    }
}

impl Default for Body {
    fn default() -> Self {
        Self {
            factory: None,
            semicolon_for_empty: true,
        }
    }
}