MetaCodable
MetaCodable copied to clipboard
[Feature Request] 1. Default value by InitializerClauseSyntax 2. Add `GroupedDefault` for multiple bindings 3. Some builtin type infer
This is an amazing project about swift macros.
In the past, some implementations I needed could only be achieved by customizing official codecs such as JSONDecoder/JSONEncoder. I want to make a small contribution to the improvement of this project. For example, the following features provide discussion.
1. Default value by InitializerClauseSyntax
Provide default value by InitializerClauseSyntax (decl.binding.initializer?.value).
Example:
struct Example {
@Default(10)
let int: Int /// defaul value is 10
var int2: Int = 10 /// default value is 10
@Default(10)
var int3: Int = 20 /// default value is 10 when apply `Default` attribute
var int4: Int = 4, int5: Int = 5 /// `int4` default value is 4, `int5` default value is 5
}
2. Add GroupedDefault for multiple bindings
I add a GroupedDefault member attribute like Default but attach to multiple bindings:
@attached(peer)
@available(swift 5.9)
public macro GroupedDefault<each T>(_ defaults: repeat each T) =
#externalMacro(module: "MacroPlugin", type: "GroupedDefault")
Using Example:
struct Student {
@GroupedDefault("Simon", 22)
let name: String, age: Int
@Default(60)
let grade: Int
}
3. We can infer some types like Int, Bool, String, Float, Double with var age = 10, var string = "hello"refer to MemberwiseInit project.
struct SomeInferTest {
var int = 10 /// Int
var float = 0.1 as Float /// Float
var double = 0.11 /// Double
var string = "hello" /// String
var bool = Bool() /// Bool
var date = Date() /// Date
}
So we can add default value like this:
struct Student {
var name = "unknown", age = 0
var grade = 60
}
Same as:
struct Student {
var name: String = "unknown", age: Int = 0
var grade: Int = 60
}
and
struct Student {
@GroupedDefault("unknown", 0)
let name: String, age: Int
@Default(60)
let grade: Int
}
4.Just generate one init function.
@MemberInit
struct Student {
let name: String, age: Int
@Default(60)
let grade: Int
var isBoy: Bool = false
var isGirl: Bool = true
}
Generate 4 init function in past like this:
init(name: String, age: Int, grade: Int = 60) {
self.name = name
self.age = age
self.grade = grade
}
init(name: String, age: Int, grade: Int = 60, isBoy: Bool) {
self.name = name
self.age = age
self.grade = grade
self.isBoy = isBoy
}
init(name: String, age: Int, grade: Int = 60, isGirl: Bool) {
self.name = name
self.age = age
self.grade = grade
self.isGirl = isGirl
}
init(name: String, age: Int, grade: Int = 60, isBoy: Bool, isGirl: Bool) {
self.name = name
self.age = age
self.grade = grade
self.isBoy = isBoy
self.isGirl = isGirl
}
But now expand 1 init function like this:
init(name: String, age: Int, grade: Int = 60, isBoy: Bool = false, isGirl: Bool = true) {
self.name = name
self.age = age
self.grade = grade
self.isBoy = isBoy
self.isGirl = isGirl
}
Thanks @SouHanaQiao for this contribution. Please create separate PRs for each feature contribution, this will help in reviewing PRs and also auto changelog generation happens per PR.