From 7425a118030d080acd025bbdbc7a2bc4ccc80058 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 31 Jan 2024 14:39:01 +0900 Subject: [PATCH] refactor(go): simplify indenting logic Use a dedicated type that implements the `Display` trait, which allows for a much simpler way of expressing and forwarding indents. --- crates/mabo-go/src/decode.rs | 124 +++++++++------------- crates/mabo-go/src/definition.rs | 30 ++++-- crates/mabo-go/src/encode.rs | 171 ++++++++++++++---------------- crates/mabo-go/src/lib.rs | 22 ++++ crates/mabo-go/src/size.rs | 173 ++++++++++++++----------------- 5 files changed, 245 insertions(+), 275 deletions(-) diff --git a/crates/mabo-go/src/decode.rs b/crates/mabo-go/src/decode.rs index 64c9fbe..b2fd0ef 100644 --- a/crates/mabo-go/src/decode.rs +++ b/crates/mabo-go/src/decode.rs @@ -4,7 +4,10 @@ use std::fmt::{self, Display}; use mabo_compiler::simplify::{FieldKind, Fields, Struct, Type, Variant}; -use crate::definition::{self, RenderGenericNames}; +use crate::{ + definition::{self, RenderGenericNames}, + Indent, +}; pub(super) struct RenderStruct<'a>(pub(super) &'a Struct<'a>); @@ -142,8 +145,8 @@ impl Display for RenderFields<'_> { "\t\t\t\tr2, value, err := {}", RenderType { ty: &field.ty, - indent: 4 - } + indent: Indent(4), + }, )?; writeln!(f, "\t\t\t\tif err != nil {{")?; writeln!(f, "\t\t\t\t\treturn nil, err")?; @@ -152,12 +155,12 @@ impl Display for RenderFields<'_> { writeln!( f, "\t\t\t\tv.{} = value", - heck::AsUpperCamelCase(&field.name) + heck::AsUpperCamelCase(&field.name), )?; writeln!( f, "\t\t\t\tfound{} = true", - heck::AsUpperCamelCase(&field.name) + heck::AsUpperCamelCase(&field.name), )?; } @@ -167,7 +170,7 @@ impl Display for RenderFields<'_> { struct RenderType<'a> { ty: &'a Type<'a>, - indent: usize, + indent: Indent, } impl Display for RenderType<'_> { @@ -290,42 +293,21 @@ impl Display for RenderType<'_> { for (idx, ty) in types.iter().enumerate() { writeln!( f, - "{:\t todo!("compiler should catch invalid tuple with {n} elements"), }, @@ -338,15 +320,14 @@ impl Display for RenderType<'_> { )?; writeln!( f, - "{:\t todo!("arrays with larger ({n}) sizes"), }, @@ -358,18 +339,12 @@ impl Display for RenderType<'_> { )?; writeln!( f, - "{:\t { struct DecodeGenericSingle<'a> { name: &'static str, ty: &'a Type<'a>, - indent: usize, + indent: Indent, } impl Display for DecodeGenericSingle<'_> { @@ -391,22 +366,21 @@ impl Display for DecodeGenericSingle<'_> { )?; writeln!( f, - "{:\t { name: &'static str, pair: &'a (Type<'a>, Type<'a>), - indent: usize, + indent: Indent, } impl Display for DecodeGenericPair<'_> { @@ -418,45 +392,41 @@ impl Display for DecodeGenericPair<'_> { definition::RenderType(&self.pair.0), definition::RenderType(&self.pair.1) )?; - writeln!(f, "{:\t(&'a str, Option<&'a [&'a str]>); impl Display for RenderPackage<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(comment) = self.1 { - write!(f, "{}", RenderComment { indent: 0, comment })?; + write!( + f, + "{}", + RenderComment { + indent: Indent(0), + comment + } + )?; } writeln!(f, "package {}\n", heck::AsSnakeCase(self.0)) @@ -129,7 +136,7 @@ impl Display for RenderStruct<'_> { f, "{}type {}{} {}", RenderComment { - indent: 0, + indent: Indent(0), comment: &self.0.comment }, heck::AsUpperCamelCase(&self.0.name), @@ -293,7 +300,7 @@ impl Display for RenderFields<'_> { f, "{}\t{} {}", RenderComment { - indent: 1, + indent: Indent(1), comment: &field.comment }, heck::AsUpperCamelCase(&field.name), @@ -358,7 +365,7 @@ impl Display for RenderAlias<'_> { f, "{}type {} {}", RenderComment { - indent: 0, + indent: Indent(0), comment: &self.0.comment, }, heck::AsUpperCamelCase(&self.0.name), @@ -368,14 +375,15 @@ impl Display for RenderAlias<'_> { } struct RenderComment<'a> { - indent: usize, + indent: Indent, comment: &'a [&'a str], } impl Display for RenderComment<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for line in self.comment { - writeln!(f, "{:\t { f, "{}{kind} {} {} = {}", RenderComment { - indent: 0, + indent: Indent(0), comment: &self.0.comment }, heck::AsUpperCamelCase(&self.0.name), @@ -582,7 +590,7 @@ impl Display for RenderEnum<'_> { f, "\n{}type {} {1}Variant", RenderComment { - indent: 0, + indent: Indent(0), comment: &self.0.comment }, heck::AsUpperCamelCase(&self.0.name), @@ -616,7 +624,7 @@ impl Display for RenderEnumVariant<'_> { f, "{}type {}_{}{} {}", RenderComment { - indent: 0, + indent: Indent(0), comment: &self.variant.comment }, heck::AsUpperCamelCase(self.enum_name), diff --git a/crates/mabo-go/src/encode.rs b/crates/mabo-go/src/encode.rs index 315353e..56f247c 100644 --- a/crates/mabo-go/src/encode.rs +++ b/crates/mabo-go/src/encode.rs @@ -4,7 +4,10 @@ use std::fmt::{self, Display}; use mabo_compiler::simplify::{FieldKind, Fields, Struct, Type, Variant}; -use crate::definition::{self, RenderGenericNames}; +use crate::{ + definition::{self, RenderGenericNames}, + Indent, +}; pub(super) struct RenderStruct<'a>(pub(super) &'a Struct<'a>); @@ -86,7 +89,7 @@ impl Display for RenderFields<'_> { RenderType { ty, name: "v", - indent: 2, + indent: Indent(2), }, )?; } else { @@ -97,7 +100,7 @@ impl Display for RenderFields<'_> { RenderType { ty: &field.ty, name: format_args!("v.{}", heck::AsUpperCamelCase(&field.name)), - indent: 2, + indent: Indent(2), }, )?; } @@ -110,53 +113,52 @@ impl Display for RenderFields<'_> { struct RenderType<'a, T> { ty: &'a Type<'a>, name: T, - indent: usize, + indent: Indent, } impl Display for RenderType<'_, T> where - T: Display, + T: Copy + Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty { - Type::Bool => write!(f, "buf.EncodeBool(w, {})", self.name), - Type::U8 => write!(f, "buf.EncodeU8(w, {})", self.name), - Type::U16 => write!(f, "buf.EncodeU16(w, {})", self.name), - Type::U32 => write!(f, "buf.EncodeU32(w, {})", self.name), - Type::U64 => write!(f, "buf.EncodeU64(w, {})", self.name), - Type::U128 => write!(f, "buf.EncodeU128(w, {})", self.name), - Type::I8 => write!(f, "buf.EncodeI8(w, {})", self.name), - Type::I16 => write!(f, "buf.EncodeI16(w, {})", self.name), - Type::I32 => write!(f, "buf.EncodeI32(w, {})", self.name), - Type::I64 => write!(f, "buf.EncodeI64(w, {})", self.name), - Type::I128 => write!(f, "buf.EncodeI128(w, {})", self.name), - Type::F32 => write!(f, "buf.EncodeF32(w, {})", self.name), - Type::F64 => write!(f, "buf.EncodeF64(w, {})", self.name), + let Self { ty, name, indent } = *self; + match ty { + Type::Bool => write!(f, "buf.EncodeBool(w, {name})"), + Type::U8 => write!(f, "buf.EncodeU8(w, {name})"), + Type::U16 => write!(f, "buf.EncodeU16(w, {name})"), + Type::U32 => write!(f, "buf.EncodeU32(w, {name})"), + Type::U64 => write!(f, "buf.EncodeU64(w, {name})"), + Type::U128 => write!(f, "buf.EncodeU128(w, {name})"), + Type::I8 => write!(f, "buf.EncodeI8(w, {name})"), + Type::I16 => write!(f, "buf.EncodeI16(w, {name})"), + Type::I32 => write!(f, "buf.EncodeI32(w, {name})"), + Type::I64 => write!(f, "buf.EncodeI64(w, {name})"), + Type::I128 => write!(f, "buf.EncodeI128(w, {name})"), + Type::F32 => write!(f, "buf.EncodeF32(w, {name})"), + Type::F64 => write!(f, "buf.EncodeF64(w, {name})"), Type::String | Type::StringRef | Type::BoxString => { - write!(f, "buf.EncodeString(w, {})", self.name) + write!(f, "buf.EncodeString(w, {name})") } Type::Bytes | Type::BytesRef | Type::BoxBytes => { - write!(f, "buf.EncodeBytes(w, {})", self.name) + write!(f, "buf.EncodeBytes(w, {name})") } Type::Vec(ty) => { writeln!( f, - "buf.EncodeVec[{}](w, {}, func(w []byte, v {0}) []byte {{", + "buf.EncodeVec[{}](w, {name}, func(w []byte, v {0}) []byte {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t { writeln!( @@ -165,106 +167,92 @@ where definition::RenderType(&kv.0), definition::RenderType(&kv.1) )?; - writeln!( - f, - "{:\t { writeln!( f, - "buf.EncodeHashSet[{}](w, {}, func(w []byte, v {0}) []byte {{", + "buf.EncodeHashSet[{}](w, {name}, func(w []byte, v {0}) []byte {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t { writeln!( f, - "buf.EncodeOption[{}](w, {}, func(w []byte, v {0}) []byte {{", + "buf.EncodeOption[{}](w, {name}, func(w []byte, v {0}) []byte {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t match &**ty { - Type::U8 => write!(f, "buf.EncodeU8(w, {}.Get())", self.name), - Type::U16 => write!(f, "buf.EncodeU16(w, {}.Get())", self.name), - Type::U32 => write!(f, "buf.EncodeU32(w, {}.Get())", self.name), - Type::U64 => write!(f, "buf.EncodeU64(w, {}.Get())", self.name), - Type::U128 => write!(f, "buf.EncodeU128(w, {}.Get())", self.name), - Type::I8 => write!(f, "buf.EncodeI8(w, {}.Get())", self.name), - Type::I16 => write!(f, "buf.EncodeI16(w, {}.Get())", self.name), - Type::I32 => write!(f, "buf.EncodeI32(w, {}.Get())", self.name), - Type::I64 => write!(f, "buf.EncodeI64(w, {}.Get())", self.name), - Type::I128 => write!(f, "buf.EncodeI128(w, {}.Get())", self.name), + Type::U8 => write!(f, "buf.EncodeU8(w, {name}.Get())"), + Type::U16 => write!(f, "buf.EncodeU16(w, {name}.Get())"), + Type::U32 => write!(f, "buf.EncodeU32(w, {name}.Get())"), + Type::U64 => write!(f, "buf.EncodeU64(w, {name}.Get())"), + Type::U128 => write!(f, "buf.EncodeU128(w, {name}.Get())"), + Type::I8 => write!(f, "buf.EncodeI8(w, {name}.Get())"), + Type::I16 => write!(f, "buf.EncodeI16(w, {name}.Get())"), + Type::I32 => write!(f, "buf.EncodeI32(w, {name}.Get())"), + Type::I64 => write!(f, "buf.EncodeI64(w, {name}.Get())"), + Type::I128 => write!(f, "buf.EncodeI128(w, {name}.Get())"), Type::String | Type::StringRef | Type::Bytes @@ -276,8 +264,8 @@ where "{}", RenderType { ty, - name: format_args!("{}.Get()", self.name), - indent: self.indent, + name: format_args!("{name}.Get()"), + indent, } ), ty => todo!("compiler should catch invalid {ty:?} type"), @@ -288,18 +276,17 @@ where for (idx, ty) in types.iter().enumerate() { writeln!( f, - "{:\t todo!("compiler should catch invalid tuple with {n} elements"), }, @@ -307,26 +294,24 @@ where 1..=32 => { writeln!( f, - "buf.EncodeArray{size}[{}](w, {}, func(w []byte, v {0}) []byte {{", + "buf.EncodeArray{size}[{}](w, {name}, func(w []byte, v {0}) []byte {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t todo!("arrays with larger ({n}) sizes"), }, - Type::External(_) => write!(f, "{}.Encode(w)", self.name), + Type::External(_) => write!(f, "{name}.Encode(w)"), } } } diff --git a/crates/mabo-go/src/lib.rs b/crates/mabo-go/src/lib.rs index 9e11c7e..a4a126a 100644 --- a/crates/mabo-go/src/lib.rs +++ b/crates/mabo-go/src/lib.rs @@ -1,5 +1,10 @@ //! Schema to source code converter for the _Go_ programming language. +use std::{ + fmt::{self, Display}, + ops::Add, +}; + pub use definition::render_schema; mod decode; @@ -30,3 +35,20 @@ pub struct Output<'a> { /// All modules that were defined as direct children of this module. pub modules: Vec>, } + +#[derive(Clone, Copy)] +struct Indent(usize); + +impl Display for Indent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:\t for Indent { + type Output = Self; + + fn add(self, rhs: usize) -> Self::Output { + Self(self.0 + rhs) + } +} diff --git a/crates/mabo-go/src/size.rs b/crates/mabo-go/src/size.rs index 771df8d..0333dff 100644 --- a/crates/mabo-go/src/size.rs +++ b/crates/mabo-go/src/size.rs @@ -4,7 +4,10 @@ use std::fmt::{self, Display}; use mabo_compiler::simplify::{FieldKind, Fields, Struct, Type, Variant}; -use crate::definition::{self, RenderGenericNames}; +use crate::{ + definition::{self, RenderGenericNames}, + Indent, +}; pub(super) struct RenderStruct<'a>(pub(super) &'a Struct<'a>); @@ -88,7 +91,7 @@ impl Display for RenderFields<'_> { RenderType { ty, name: "v", - indent: 2, + indent: Indent(2), }, )?; } else { @@ -99,7 +102,7 @@ impl Display for RenderFields<'_> { RenderType { ty: &field.ty, name: format_args!("v.{}", heck::AsUpperCamelCase(&field.name)), - indent: 2, + indent: Indent(2), }, )?; } @@ -112,53 +115,52 @@ impl Display for RenderFields<'_> { struct RenderType<'a, T> { ty: &'a Type<'a>, name: T, - indent: usize, + indent: Indent, } impl Display for RenderType<'_, T> where - T: Display, + T: Copy + Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty { - Type::Bool => write!(f, "buf.SizeBool({})", self.name), - Type::U8 => write!(f, "buf.SizeU8({})", self.name), - Type::U16 => write!(f, "buf.SizeU16({})", self.name), - Type::U32 => write!(f, "buf.SizeU32({})", self.name), - Type::U64 => write!(f, "buf.SizeU64({})", self.name), - Type::U128 => write!(f, "buf.SizeU128({})", self.name), - Type::I8 => write!(f, "buf.SizeI8({})", self.name), - Type::I16 => write!(f, "buf.SizeI16({})", self.name), - Type::I32 => write!(f, "buf.SizeI32({})", self.name), - Type::I64 => write!(f, "buf.SizeI64({})", self.name), - Type::I128 => write!(f, "buf.SizeI128({})", self.name), - Type::F32 => write!(f, "buf.SizeF32({})", self.name), - Type::F64 => write!(f, "buf.SizeF64({})", self.name), + let Self { ty, name, indent } = *self; + match ty { + Type::Bool => write!(f, "buf.SizeBool({name})"), + Type::U8 => write!(f, "buf.SizeU8({name})"), + Type::U16 => write!(f, "buf.SizeU16({name})"), + Type::U32 => write!(f, "buf.SizeU32({name})"), + Type::U64 => write!(f, "buf.SizeU64({name})"), + Type::U128 => write!(f, "buf.SizeU128({name})"), + Type::I8 => write!(f, "buf.SizeI8({name})"), + Type::I16 => write!(f, "buf.SizeI16({name})"), + Type::I32 => write!(f, "buf.SizeI32({name})"), + Type::I64 => write!(f, "buf.SizeI64({name})"), + Type::I128 => write!(f, "buf.SizeI128({name})"), + Type::F32 => write!(f, "buf.SizeF32({name})"), + Type::F64 => write!(f, "buf.SizeF64({name})"), Type::String | Type::StringRef | Type::BoxString => { - write!(f, "buf.SizeString({})", self.name) + write!(f, "buf.SizeString({name})") } Type::Bytes | Type::BytesRef | Type::BoxBytes => { - write!(f, "buf.SizeBytes({})", self.name) + write!(f, "buf.SizeBytes({name})") } Type::Vec(ty) => { writeln!( f, - "buf.SizeVec[{}]({}, func(v {0}) int {{", + "buf.SizeVec[{}]({name}, func(v {0}) int {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t { writeln!( @@ -167,106 +169,92 @@ where definition::RenderType(&kv.0), definition::RenderType(&kv.1) )?; - writeln!( - f, - "{:\t { writeln!( f, - "buf.SizeHashSet[{}]({}, func(v {0}) int {{", + "buf.SizeHashSet[{}]({name}, func(v {0}) int {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t { writeln!( f, - "buf.SizeOption[{}]({}, func(v {0}) int {{", + "buf.SizeOption[{}]({name}, func(v {0}) int {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t match &**ty { - Type::U8 => write!(f, "buf.SizeU8({}.Get())", self.name), - Type::U16 => write!(f, "buf.SizeU16({}.Get())", self.name), - Type::U32 => write!(f, "buf.SizeU32({}.Get())", self.name), - Type::U64 => write!(f, "buf.SizeU64({}.Get())", self.name), - Type::U128 => write!(f, "buf.SizeU128({}.Get())", self.name), - Type::I8 => write!(f, "buf.SizeI8({}.Get())", self.name), - Type::I16 => write!(f, "buf.SizeI16({}.Get())", self.name), - Type::I32 => write!(f, "buf.SizeI32({}.Get())", self.name), - Type::I64 => write!(f, "buf.SizeI64({}.Get())", self.name), - Type::I128 => write!(f, "buf.SizeI128({}.Get())", self.name), + Type::U8 => write!(f, "buf.SizeU8({name}.Get())"), + Type::U16 => write!(f, "buf.SizeU16({name}.Get())"), + Type::U32 => write!(f, "buf.SizeU32({name}.Get())"), + Type::U64 => write!(f, "buf.SizeU64({name}.Get())"), + Type::U128 => write!(f, "buf.SizeU128({name}.Get())"), + Type::I8 => write!(f, "buf.SizeI8({name}.Get())"), + Type::I16 => write!(f, "buf.SizeI16({name}.Get())"), + Type::I32 => write!(f, "buf.SizeI32({name}.Get())"), + Type::I64 => write!(f, "buf.SizeI64({name}.Get())"), + Type::I128 => write!(f, "buf.SizeI128({name}.Get())"), Type::String | Type::StringRef | Type::Bytes @@ -278,8 +266,8 @@ where "{}", RenderType { ty, - name: format_args!("{}.Get()", self.name), - indent: self.indent, + name: format_args!("{name}.Get()"), + indent, } ), ty => todo!("compiler should catch invalid {ty:?} type"), @@ -287,22 +275,21 @@ where Type::Tuple(types) => match types.len() { 2..=12 => { writeln!(f, "func() int {{")?; - writeln!(f, "{:\t todo!("compiler should catch invalid tuple with {n} elements"), }, @@ -310,26 +297,24 @@ where 1..=32 => { writeln!( f, - "buf.SizeArray{size}[{}]({}, func(v {0}) int {{", + "buf.SizeArray{size}[{}]({name}, func(v {0}) int {{", definition::RenderType(ty), - self.name )?; writeln!( f, - "{:\t todo!("arrays with larger ({n}) sizes"), }, - Type::External(_) => write!(f, "{}.Size()", self.name), + Type::External(_) => write!(f, "{name}.Size()"), } } }