use std::fmt;
#[derive(Clone, Copy, Debug)]
pub enum IndentationStyle {
Allman,
GNU,
Whitesmiths,
KnR,
Ratliff,
Horstmann,
Pico,
Lisp,
None,
}
#[derive(Clone, Copy, Debug)]
pub enum CaseType {
FlatCase,
ScreamingCase,
CamelCase,
PascalCase,
SnakeCase,
ScreamingSnakeCase
}
#[derive(Copy, Clone)]
pub enum IndentationType {
Spaces,
Tabs,
}
#[derive(Clone, Copy)]
pub enum NewLineType {
Cr,
Nl,
CrNl,
None,
}
#[derive(Clone, Copy, Debug)]
pub enum CodeStyle {
Allman,
GNU,
Whitesmiths,
KnR,
Ratliff,
Horstmann,
Pico,
Lisp,
Minimal,
GeneratOR,
}
#[derive(Copy, Clone, PartialEq)]
pub enum GeneratorContext {
If,
While,
ForLoop,
Function,
File,
Struct,
Enum,
Other,
}
#[derive(Copy, Clone)]
pub struct CodeGenerationInfo {
pub indent_level: usize,
pub indent_type: IndentationType,
pub indent_amount: usize,
pub indent_style: IndentationStyle,
pub new_line_type: NewLineType,
pub context: GeneratorContext,
pub function_name_case: CaseType,
pub member_name_case: CaseType,
pub type_name_case: CaseType,
pub default_name_case: CaseType,
}
pub struct DisplayHandler<'a> {
generator: &'a dyn CodeGenerate,
info: CodeGenerationInfo,
}
impl<'a> DisplayHandler<'a> {
pub fn new(gen: &'a dyn CodeGenerate, info: CodeGenerationInfo) -> DisplayHandler<'a> {
DisplayHandler { generator: gen, info: info }
}
}
impl fmt::Display for DisplayHandler<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.generator.generate(f, self.info)
}
}
impl CodeGenerationInfo {
pub fn new() -> CodeGenerationInfo {
CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Allman,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
}
}
pub const fn from_style(code_style: CodeStyle) -> CodeGenerationInfo {
match code_style {
CodeStyle::Allman => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Allman,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::GNU => CodeGenerationInfo {
indent_level: 0,
indent_amount: 2,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::GNU,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Horstmann => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Horstmann,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::KnR => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::KnR,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Lisp => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Lisp,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Minimal => CodeGenerationInfo {
indent_level: 0,
indent_amount: 0,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::None,
new_line_type: NewLineType::None,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Pico => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Pico,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Ratliff => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Ratliff,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::Whitesmiths => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Spaces,
indent_style: IndentationStyle::Whitesmiths,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
CodeStyle::GeneratOR => CodeGenerationInfo {
indent_level: 0,
indent_amount: 4,
indent_type: IndentationType::Tabs,
indent_style: IndentationStyle::KnR,
new_line_type: NewLineType::CrNl,
context: GeneratorContext::File,
function_name_case: CaseType::CamelCase,
member_name_case: CaseType::SnakeCase,
type_name_case: CaseType::PascalCase,
default_name_case: CaseType::FlatCase,
},
}
}
pub fn indent(&self) -> CodeGenerationInfo {
let mut info = *self;
info.indent_level += 1;
info
}
pub fn with_context(&mut self, context: GeneratorContext) -> CodeGenerationInfo {
let mut info = *self;
info.context = context;
info
}
}
pub trait CodeGenerate {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result;
}
pub trait DisplayExt {
fn display(self: &Self, info: CodeGenerationInfo) -> DisplayHandler;
}
impl<T> DisplayExt for T
where T: CodeGenerate {
fn display(self: &Self, info: CodeGenerationInfo) -> DisplayHandler {
DisplayHandler::new(self, info)
}
}
pub struct Indentation {
}
impl Indentation {
pub fn new() -> Indentation {
Indentation { }
}
}
impl CodeGenerate for Indentation {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let indent ;
match info.indent_type {
IndentationType::Spaces => indent = " ".repeat(info.indent_amount*info.indent_level),
IndentationType::Tabs => indent = " ".repeat(
((info.indent_amount+3) / 4) * info.indent_level
),
}
write!(f, "{}", indent)
}
}
pub enum NameType {
Default,
Type,
Member,
Function,
FixedCase(CaseType),
}
pub struct Name {
parts: Vec<String>,
name_type: NameType
}
impl Name {
pub fn new(screaming_snake_case_name: &str) -> Name {
let name = screaming_snake_case_name;
let mut parts = Vec::<String>::new();
for entry in name.split("_") {
if !entry.is_empty() {
parts.push(entry.to_ascii_lowercase());
}
}
if parts.len() == 0 {
parts.push("invalid".into());
parts.push("name".into());
}
Name {
parts: parts,
name_type: NameType::Default
}
}
pub fn new_with_type(screaming_snake_case_name: &str, name_type: NameType) -> Name {
Name::new(screaming_snake_case_name).with_type(name_type)
}
pub fn with_type(mut self, name_type: NameType) -> Name {
self.name_type = name_type;
self
}
fn caps_first_letter(string: String) -> String {
let mut result = String::new();
let mut iter = string.chars();
if let Some(char) = iter.next() {
result.push(char.to_ascii_uppercase());
}
for char in iter {
result.push(char);
}
result
}
fn casify(&self, case: CaseType) -> String {
let mut parts = Vec::new();
let mut is_first = true;
for part in self.parts.iter() {
parts.push (match case {
CaseType::CamelCase => if is_first {part.clone()} else {Self::caps_first_letter(part.clone())},
CaseType::FlatCase => part.clone(),
CaseType::PascalCase => Self::caps_first_letter(part.clone()),
CaseType::ScreamingCase => part.to_ascii_uppercase(),
CaseType::ScreamingSnakeCase => part.to_ascii_uppercase(),
CaseType::SnakeCase => part.clone(),
});
is_first = false;
}
match case {
CaseType::CamelCase => parts.join(""),
CaseType::FlatCase => parts.join(""),
CaseType::PascalCase => parts.join(""),
CaseType::ScreamingCase => parts.join(""),
CaseType::ScreamingSnakeCase => parts.join("_"),
CaseType::SnakeCase => parts.join("_"),
}
}
fn get_case_type(&self, info: CodeGenerationInfo) -> CaseType {
match self.name_type {
NameType::Default => info.default_name_case,
NameType::Function => info.function_name_case,
NameType::Member => info.member_name_case,
NameType::Type => info.type_name_case,
NameType::FixedCase(case) => case,
}
}
}
impl CodeGenerate for Name {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let case_type = self.get_case_type(info);
write!(f, "{}", self.casify(case_type))
}
}
pub struct NewLine {
}
impl NewLine {
pub fn new() -> NewLine {
NewLine { }
}
}
impl CodeGenerate for NewLine {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
match info.new_line_type {
NewLineType::Cr => write!(f, "\r"),
NewLineType::Nl => write!(f, "\n"),
NewLineType::CrNl => write!(f, "\r\n"),
NewLineType::None => write!(f, ""),
}
}
}
pub struct CodeSet {
code_set: Vec<Box<dyn CodeGenerate>>,
}
impl CodeSet {
pub fn new(set: Vec<Box<dyn CodeGenerate>>) -> CodeSet {
CodeSet { code_set: set }
}
}
impl CodeGenerate for CodeSet {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result = fmt::Result::Ok(());
let mut iter = self.code_set.iter();
if let Some(item) = iter.next() {
result = result.and(item.generate(f, info));
for item in iter {
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(item.generate(f, info));
}
}
result
}
}
pub struct JoinedCode {
code_set: Vec<Box<dyn CodeGenerate>>,
}
impl JoinedCode {
pub fn new(set: Vec<Box<dyn CodeGenerate>>) -> JoinedCode {
JoinedCode { code_set: set }
}
}
impl CodeGenerate for JoinedCode {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result = fmt::Result::Ok(());
for item in self.code_set.iter() {
result = result.and(item.generate(f, info));
}
result
}
}
pub struct RawCode {
text: String,
}
impl RawCode {
pub fn new(code: &str) -> RawCode {
RawCode { text: code.to_string() }
}
pub fn merge(mut self, other: RawCode) -> RawCode {
self.text.push_str(other.text.as_str());
self
}
}
impl CodeGenerate for RawCode {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
if let Some(line) = self.text.lines().next() {
result = result.and(result.and(write!(f, "{}", line)));
for line in self.text.lines().skip(1) {
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{}", line));
}
}
return result;
}
}
impl CodeGenerate for String {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
if let Some(line) = self.lines().next() {
result = result.and(result.and(write!(f, "{}", line)));
for line in self.lines().skip(1) {
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{}", line));
}
}
return result;
}
}
pub struct SeparatedCode {
items: Vec<Box<dyn CodeGenerate>>,
separator: Box<dyn CodeGenerate>,
}
impl SeparatedCode {
pub fn new(items: Vec<Box<dyn CodeGenerate>>, separator: Box<dyn CodeGenerate>) -> SeparatedCode {
SeparatedCode { items: items, separator: separator }
}
}
impl CodeGenerate for SeparatedCode {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
let mut iterator = self.items.iter();
if let Some(item) = iterator.next() {
result = result.and(item.generate(f, info));
}
for item in iterator {
result = result.and(self.separator.generate(f, info));
result = result.and(item.generate(f, info));
}
result
}
}
pub struct CodeBody {
raw_code: CodeSet,
}
impl CodeBody {
pub fn new(code: Vec<Box<dyn CodeGenerate>>) -> CodeBody {
CodeBody {raw_code: CodeSet::new(code)}
}
}
impl CodeGenerate for CodeBody {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
match info.indent_style {
IndentationStyle::Allman => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent()));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::GNU => {
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent().indent()));
result = result.and(self.raw_code.generate(f, info.indent().indent()));
result = result.and(NewLine::new().generate(f, info));
if info.context != GeneratorContext::Function {
result = result.and(Indentation::new().generate(f, info.indent()));
}
result = result.and(write!(f, "}}"));
}
IndentationStyle::Horstmann => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
let mut temp_info = info;
temp_info.indent_level = 1;
temp_info.indent_amount -= 1;result = result.and(Indentation::new().generate(f, temp_info));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::KnR => {
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent()));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::Pico => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
let mut temp_info = info;
temp_info.indent_level = 1;
temp_info.indent_amount -= 1;result = result.and(Indentation::new().generate(f, temp_info));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(write!(f, " }}"));
}
IndentationStyle::None => {
result = result.and(write!(f, "{{"));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(write!(f, "}}"));
}
_ => result = result.and(write!(f, "NOT SUPPORTED YET!")),
}
result
}
}
pub struct HeaderPlusBody<HT> {
header: HT,
body: CodeBody,
}
impl<HT> HeaderPlusBody<HT> {
pub fn new(header: HT, body: CodeBody) -> HeaderPlusBody<HT>{
HeaderPlusBody {header: header, body: body}
}
}
impl<HT> CodeGenerate for HeaderPlusBody<HT>
where HT: CodeGenerate,{
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
result = result.and(self.header.generate(f, info));
match info.indent_style {
IndentationStyle::Allman |
IndentationStyle::Horstmann |
IndentationStyle::Pico => {
result = result.and(NewLine::new().generate(f, info));
},
IndentationStyle::GNU => {
result = result.and(NewLine::new().generate(f, info));
if info.context != GeneratorContext::Function {
result = result.and(Indentation::new().generate(f, info.indent()));
}
}
IndentationStyle::KnR => {
result = result.and(write!(f, " "));
}
_ => (),
}
result = result.and(self.body.generate(f, info));
result
}
}
pub struct IfStatement {
content: HeaderPlusBody<JoinedCode>,
}
impl IfStatement {
pub fn new<CT>(condition: CT, body: CodeBody) -> IfStatement
where CT: CodeGenerate + 'static {
IfStatement {
content: HeaderPlusBody::new(
JoinedCode::new(
vec![
Box::new(String::from("if (")),
Box::new(condition),
Box::new(String::from(")"))
]
),
body
)
}
}
}
impl CodeGenerate for IfStatement {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::If;
self.content.generate(f, info)
}
}
pub struct WhileStatement {
content: HeaderPlusBody<JoinedCode>,
}
impl WhileStatement {
pub fn new(condition: RawCode, body: CodeBody) -> WhileStatement {
WhileStatement {
content: HeaderPlusBody::new(
JoinedCode::new(
vec![
Box::new(String::from("while (")),
Box::new(condition),
Box::new(String::from(")"))
]
),
body
)
}
}
}
impl CodeGenerate for WhileStatement {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::While;
self.content.generate(f, info)
}
}
pub struct ForLoop {
content: HeaderPlusBody<JoinedCode>,
}
impl ForLoop {
pub fn new<IT, CT, UT>(init_code: IT, continuation_code: CT, update_code: UT, body: Vec<Box<dyn CodeGenerate>>) -> ForLoop
where IT: CodeGenerate + 'static,
CT: CodeGenerate + 'static,
UT: CodeGenerate + 'static {
ForLoop { content: HeaderPlusBody::new(
JoinedCode::new(vec![
Box::new(String::from("for (")),
Box::new(init_code),
Box::new(String::from("; ")),
Box::new(continuation_code),
Box::new(String::from("; ")),
Box::new(update_code),
Box::new(String::from(")")),
]),
CodeBody::new(body)
) }
}
}
impl CodeGenerate for ForLoop {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::ForLoop;
self.content.generate(f, info)
}
}
pub struct FunctionSignature {
function_name: Name,
parameters: SeparatedCode,
return_type: Name,
}
impl FunctionSignature {
pub fn new(return_type: Name, name: Name, parameters: Vec<(Name, Name)>) -> FunctionSignature {
let mut set = Vec::<Box<dyn CodeGenerate>>::new();
for (type_name, param_name) in parameters {
set.push(Box::new(JoinedCode::new(vec![Box::new(type_name.with_type(NameType::Type)), Box::new(String::from(" ")), Box::new(param_name.with_type(NameType::Member))])))
}
FunctionSignature {
return_type: return_type.with_type(NameType::Type),
function_name: name.with_type(NameType::Function),
parameters: SeparatedCode::new(set, Box::new(String::from(", "))),
}
}
}
impl CodeGenerate for FunctionSignature {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
result = result.and(self.return_type.generate(f, info));
result = result.and(write!(f, " "));
result = result.and(self.function_name.generate(f, info));
result = result.and(write!(f, "("));
result = result.and(self.parameters.generate(f, info));
result = result.and(write!(f, ")"));
result
}
}
pub struct FunctionDeclaration {
signature: FunctionSignature
}
impl FunctionDeclaration {
pub fn new(return_type: Name, name: Name, parameters: Vec<(Name, Name)>) -> FunctionDeclaration {
FunctionDeclaration {
signature: FunctionSignature::new(return_type, name, parameters)
}
}
}
impl CodeGenerate for FunctionDeclaration {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
result = result.and(self.signature.generate(f, info));
result = result.and(write!(f, ";"));
result
}
}
pub struct Function {
content: HeaderPlusBody<FunctionSignature>,
}
impl Function {
pub fn new(signature: FunctionSignature, body: CodeBody) -> Function {
Function {
content: HeaderPlusBody::new(signature, body)
}
}
}
impl CodeGenerate for Function {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::Function;
self.content.generate(f, info)
}
}
pub struct HeaderFile {
file_name: Name,
content: CodeSet,
}
impl HeaderFile {
pub fn new(file_name: Name, content: CodeSet) -> HeaderFile {
HeaderFile {
file_name: file_name.with_type(NameType::FixedCase(CaseType::ScreamingSnakeCase)),
content: content,
}
}
}
impl CodeGenerate for HeaderFile {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::File;
let mut result = fmt::Result::Ok(());
result = result.and(write!(f, "#ifndef {}_H", self.file_name.display(info)));
result = result.and(NewLine::new().generate(f, info));
result = result.and(write!(f, "#define {}_H", self.file_name.display(info)));
result = result.and(NewLine::new().generate(f, info));
result = result.and(NewLine::new().generate(f, info));
result = result.and(self.content.generate(f, info));
result = result.and(NewLine::new().generate(f, info));
result = result.and(NewLine::new().generate(f, info));
result = result.and(write!(f, "#endif"));
result = result.and(NewLine::new().generate(f, info));
result
}
}
pub struct Enum {
content: HeaderPlusBody<String>,
name: Name,
}
impl Enum {
pub fn new(name: Name, values: Vec<(Name, Option<i64>)>) -> Enum {
let mut code_values: Vec<Box<dyn CodeGenerate>> = Vec::new();
for (member_name, value) in values {
if let Some(value) = value {
code_values.push(Box::new(JoinedCode::new(
vec![Box::new(member_name.with_type(NameType::Type)), Box::new(format!(" = {},", value))]
)));
} else {
code_values.push(Box::new(JoinedCode::new(
vec![Box::new(member_name.with_type(NameType::Type)), Box::new(String::from(","))]
)));
}
}
Enum {
name: name.with_type(NameType::Type),
content: HeaderPlusBody::new(
String::from("typedef enum"),
CodeBody::new(code_values)
)
}
}
}
impl CodeGenerate for Enum {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::Enum;
let mut result = self.content.generate(f, info);
result = result.and(String::from(" ").generate(f, info));
result = result.and(self.name.generate(f, info));
result = result.and(String::from(";").generate(f, info));
result
}
}
pub struct Struct {
content: HeaderPlusBody<String>,
name: Name,
}
impl Struct {
pub fn new(name: Name, values: Vec<(Name, Name)>) -> Struct {
let mut code_values: Vec<Box<dyn CodeGenerate>> = Vec::new();
for (member_type, member_name) in values {
code_values.push(Box::new(JoinedCode::new(vec![
Box::new(member_type.with_type(NameType::Type)),
Box::new(String::from(" ")),
Box::new(member_name.with_type(NameType::Member)),
Box::new(String::from(";")),
])));
}
Struct {
name: name.with_type(NameType::Type),
content: HeaderPlusBody::new(
String::from("typedef struct"),
CodeBody::new(code_values)
)
}
}
}
impl CodeGenerate for Struct {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::Struct;
let mut result = self.content.generate(f, info);
result = result.and(String::from(" ").generate(f, info));
result = result.and(self.name.generate(f, info));
result = result.and(String::from(";").generate(f, info));
result
}
}
pub struct TypeDef {
defined_type: String,
name: Name,
}
impl TypeDef {
pub fn new(name: Name, defined_type: String) -> TypeDef {
TypeDef {
defined_type: defined_type,
name: name.with_type(NameType::Type)
}
}
}
impl CodeGenerate for TypeDef {
fn generate(&self, f: &mut fmt::Formatter<'_>, mut info: CodeGenerationInfo) -> fmt::Result {
info.context = GeneratorContext::Struct;
let mut result = String::from("typedef ").generate(f, info);
result = result.and(self.defined_type.generate(f, info));
result = result.and(String::from(" ").generate(f, info));
result = result.and(self.name.generate(f, info));
result = result.and(String::from(";").generate(f, info));
result
}
}