Comments (6)
Attribute を融合(merge)するのが難しいのでは?
from tsumiji.
上記は生成部分のみでした。モディファイア部分も書いておきます。
public extension Attribute {
func fontName(_ value: String) -> Attribute {
var newContext = self.context
newContext.fontName = value
return .init(context: newContext)
}
func fontSize(_ value: NSNumber) -> Attribute {
var newContext = self.context
newContext.fontSize = value
return .init(context: newContext)
}
func foregroundColor(_ value: Scope.ForegroundColorAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.foregroundColor = value
return .init(context: newContext)
}
func backgroundColor(_ value: Scope.BackgroundColorAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.backgroundColor = value
return .init(context: newContext)
}
func kern(_ value: Scope.KernAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.kern = value
return .init(context: newContext)
}
func tracking(_ value: Scope.TrackingAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.tracking = value
return .init(context: newContext)
}
func baselineOffset(_ value: Scope.BaselineOffsetAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.baselineOffset = value
return .init(context: newContext)
}
}
from tsumiji.
#34 を達成する場合は以下のような protocol を使用するといいかもしれません。
public protocol AttributeModifier {
func modify(context: inout AttributeContext)
}
extension Attribute {
func modified<Mod: AttributeModifier>(_ mod: Mod) -> Attribute {
var newContext = self.context
mod.modify(&newContext)
.init(context: newContext)
}
}
例: fontName
struct FontName: AttributeModifier {
let value: String
func modify(context: inout AttributeContext) {
context.fontName = self.value
}
}
public extension Attribute {
func fontName(_ value: String) -> Attribute {
self.modified(FontName(value))
}
}
from tsumiji.
もしこれがうまく機能する場合、enum を使う API と比較して以下のようなメリットがあると思われます。
- 仕組みがシンプルなので今後の更新が簡単になるかも。
- 多分メモリ的なパフォーマンスがいい。 <- 最終的にできる Attribute のメモリサイズが固定なので。
- 多分生成〜使用に必要な実行速度も速い。enum は switch の連続 + こちらは特に加工せず直接利用できる
from tsumiji.
この方式では、Attribute を merge することが難しいです。なぜなら、style 設計者がどのプロパティを優先したいかが分からなくなってしまうからです。しかし、方法がないわけではありません。
まず各プロパティに対応する enum を作成します(自動で Hashable
になります)。
enum ModifiedProperty {
case fontName
case fontSize
case ...
}
そして、子に列挙体の Set を用意しておきます。
let modifiedPropertyHistory: Set<ModifiedProperty>
あとは Attribute に builder で情報を付加するたびに、プロパティに対応する case をこの Set に挿入していくだけです。
struct Attribute {
enum ModifiedProperty {
case fontName
case fontSize
case ...
}
let context: AttributeContext
let modifiedPropertyHistory: Set<ModifiedProperty>
}
この手法のメリット・デメリットをメモしておきます。
- メリット
- 仕組みがシンプルなので、変更に強い。
- 重複した変更が起こらない。ビルダーに記述することはできるが、データ内部では重複が起きない。
- ただし、プログラマが重複しないように気をつけて書くことで重複は回避できます。
- デメリット
- merge するときに modified property を switch する必要があるのがとても面倒臭い。
- indirect enum の負荷と大差ないかもです。
- メモリ節約にはあまりならないかもしれない。
- ただし、Attribute の情報追加によるデータサイズ増加分は、AttributeType の挿入分のみです
- Context 部分は固定なので、情報が少なくてもそこそこのデータサイズになります。
- プログラマが新しい modifier を追加するのが難しいかもしれません。
- この柔軟性はオプションなので、放棄してもいいかもしれません。
- 列挙体ではなく、String などにすればいくらでも追加できます。
- merge の実装が難しそうです。
- merge するときに modified property を switch する必要があるのがとても面倒臭い。
from tsumiji.
ひとつ前のコメントのコードを実装するなら、というメモです。
public protocol AttributeModifier {
var propertyData: Attribute.ModifiedProperty { get }
func modify(context: inout AttributeContext)
}
extension Attribute {
func modified<Mod: AttributeModifier>(_ mod: Mod) -> Attribute {
var newContext = self.context
var newHistory = self.modifiedPropertyHistory
mod.modify(&newContext)
newHistory.insert(mod.propertyData)
return Attribute(context: newContext, modifiedPropertyHistory: newHistory)
}
}
Attribute context の merge についてもメモしておきます。
extension AttributeContext {
// 他のコンテキストを、特定のプロパティについて変異させます
func modify(_ c: inout AttributeContext, forProperty property: Attribute.ModifiedProperty) {
switch property {
case .fontName:
c.fontName = self.fontName
case .fontSize:
c.fontSize = self.fontSize
case .foregroundColor:
c.container.foregroundColor = self.foregroundColor
// ...
default:
break
}
}
}
from tsumiji.
Related Issues (12)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tsumiji.