Skip to content

Commit 3f43910

Browse files
author
Fahad Zubair
committed
Refactored RustCrateInlineWriter to use top level sets
1 parent 96e9bdf commit 3f43910

File tree

4 files changed

+245
-174
lines changed

4 files changed

+245
-174
lines changed

codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt

Lines changed: 143 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ import java.util.concurrent.ConcurrentHashMap
1212
typealias DocWriter = () -> Any
1313
typealias InlineModuleCreator = (Symbol, Writable) -> Unit
1414

15+
16+
/**
17+
* Initializes RustCrate -> InnerModule data structure.
18+
*/
19+
fun RustCrate.initializeInlineModuleWriter(debugMode : Boolean): InnerModule =
20+
crateToInlineModule
21+
.getOrPut(this) { InnerModule(debugMode) }
22+
23+
/**
24+
* Returns the InnerModule for the given RustCrate
25+
*/
26+
fun RustCrate.getInlineModuleWriter() : InnerModule {
27+
return crateToInlineModule.getOrPut(this) { InnerModule(false) }
28+
}
29+
1530
/**
1631
* Returns a function that can be used to create an inline module writer.
1732
*/
@@ -23,6 +38,80 @@ fun RustCrate.createInlineModuleCreator(): InlineModuleCreator {
2338
}
2439
}
2540

41+
/**
42+
* If the passed in `shape` is a synthetic extracted shape resulting from a constrained struct member,
43+
* the `Writable` is called using the structure's builder module. Otherwise the `Writable` is called
44+
* using the given `module`.
45+
*/
46+
fun RustCrate.withModuleOrWithStructureBuilderModule(
47+
module: RustModule,
48+
shape: Shape,
49+
codegenContext: ServerCodegenContext,
50+
codeWritable: Writable,
51+
) {
52+
// All structure constrained-member-shapes code is generated inside the structure builder's module.
53+
val parentAndInlineModuleInfo =
54+
shape.getParentAndInlineModuleForConstrainedMember(codegenContext.symbolProvider, !codegenContext.settings.codegenConfig.publicConstrainedTypes)
55+
if (parentAndInlineModuleInfo == null) {
56+
this.withModule(module, codeWritable)
57+
} else {
58+
val (parent, inline) = parentAndInlineModuleInfo
59+
val inlineWriter = this.getInlineModuleWriter()
60+
61+
inlineWriter.withInlineModuleHierarchyUsingCrate(this, parent) {
62+
inlineWriter.withInlineModuleHierarchy(this, inline) {
63+
codeWritable(this)
64+
}
65+
}
66+
}
67+
}
68+
69+
/**
70+
* If the passed in `shape` is a synthetic extracted shape resulting from a constrained struct member,
71+
* the `Writable` is called using the structure's builder module. Otherwise the `Writable` is called
72+
* using shape's `module`.
73+
*/
74+
fun RustCrate.useShapeWriterOrUseWithStructureBuilder(
75+
shape: Shape,
76+
codegenContext: ServerCodegenContext,
77+
docWriter: DocWriter? = null,
78+
writable: Writable,
79+
) {
80+
// All structure constrained-member-shapes code is generated inside the structure builder's module.
81+
val parentAndInlineModuleInfo =
82+
shape.getParentAndInlineModuleForConstrainedMember(codegenContext.symbolProvider, !codegenContext.settings.codegenConfig.publicConstrainedTypes)
83+
if (parentAndInlineModuleInfo == null) {
84+
docWriter?.invoke()
85+
this.useShapeWriter(shape, writable)
86+
} else {
87+
val (parent, inline) = parentAndInlineModuleInfo
88+
val inlineWriter = this.getInlineModuleWriter()
89+
90+
inlineWriter.withInlineModuleHierarchyUsingCrate(this, parent) {
91+
inlineWriter.withInlineModuleHierarchy(this, inline) {
92+
writable(this)
93+
}
94+
}
95+
}
96+
}
97+
98+
/**
99+
* Given a `RustWriter` calls the `Writable` using a `RustWriter` for the `inlineModule`
100+
*/
101+
fun RustCrate.withInMemoryInlineModule(
102+
outerWriter: RustWriter,
103+
inlineModule: RustModule.LeafModule,
104+
docWriter: DocWriter?,
105+
codeWritable: Writable,
106+
) {
107+
check(inlineModule.isInline()) {
108+
"module has to be an inline module for it to be used with the InlineModuleWriter"
109+
}
110+
this.getInlineModuleWriter().withInlineModuleHierarchy(outerWriter, inlineModule, docWriter) {
111+
codeWritable(this)
112+
}
113+
}
114+
26115
fun RustWriter.createTestInlineModuleCreator(): InlineModuleCreator {
27116
return { symbol: Symbol, writable: Writable ->
28117
this.withInlineModule(symbol.module()) {
@@ -31,14 +120,27 @@ fun RustWriter.createTestInlineModuleCreator(): InlineModuleCreator {
31120
}
32121
}
33122

34-
123+
/**
124+
* Maintains the `RustWriter` that has been created for a `RustModule.LeafModule`.
125+
*/
35126
private data class InlineModuleWithWriter(val inlineModule : RustModule.LeafModule, val writer : RustWriter)
36127

128+
/**
129+
* For each RustCrate a separate mapping of inline-module to `RustWriter` is maintained.
130+
*/
131+
private val crateToInlineModule: ConcurrentHashMap<RustCrate, InnerModule> =
132+
ConcurrentHashMap()
133+
37134
class InnerModule(private val debugMode : Boolean) {
38-
private val topLevelModuleWriters: HashMap<RustWriter, MutableList<InlineModuleWithWriter>> = hashMapOf()
135+
private val topLevelModuleWriters: MutableSet<RustWriter> = mutableSetOf()
39136
private val inlineModuleWriters: HashMap<RustWriter, MutableList<InlineModuleWithWriter>> = hashMapOf()
40137
private val docWriters: HashMap<RustModule.LeafModule, MutableList<DocWriter>> = hashMapOf()
41138
private val writerCreator = RustWriter.factory(debugMode)
139+
private val emptyLineCount: Int = writerCreator
140+
.apply("lines-it-always-writes.rs", "crate")
141+
.toString()
142+
.split("\n")[0]
143+
.length
42144

43145
private fun createNewInlineModule(): RustWriter {
44146
val writer = writerCreator.apply("unknown-module-would-never-be-written.rs", "crate")
@@ -67,7 +169,9 @@ class InnerModule(private val debugMode : Boolean) {
67169
val bottomMost = hierarchy.removeLast()
68170

69171
// In case it is a top level module that has been passed (e.g. ModelsModule, OutputsModule) then
70-
// register it with the topLevel HashMap and call the writable on it.
172+
// register it with the topLevel writers and call the writable on it. Otherwise, go over the
173+
// complete hierarchy, registering each of the inner modules and then call the `Writable`
174+
// with the bottom most inline module that has been passed.
71175
if (hierarchy.isNotEmpty()) {
72176
val topMost = hierarchy.removeFirst()
73177

@@ -80,8 +184,7 @@ class InnerModule(private val debugMode : Boolean) {
80184

81185
withInlineModule(writer, bottomMost as RustModule.LeafModule, docWriter, writable)
82186
}
83-
}
84-
else {
187+
} else {
85188
check(!bottomMost.isInline()) {
86189
"there is only one module in hierarchy so it has to be non-inlined"
87190
}
@@ -137,55 +240,63 @@ class InnerModule(private val debugMode : Boolean) {
137240
* Writes out each inline module's code (`toString`) to the respective top level `RustWriter`.
138241
*/
139242
fun render() {
140-
fun renderDescendents(writer: RustWriter, inMemoryWriter: RustWriter) {
141-
val innerModuleCode = inMemoryWriter.toString()
142-
writer.writeWithNoFormatting(innerModuleCode)
243+
fun writeInlineCode(rustWriter: RustWriter, code: String) {
244+
val inlineCode = code.drop(emptyLineCount)
245+
rustWriter.writeWithNoFormatting(inlineCode)
246+
}
247+
248+
fun renderDescendents(topLevelWriter: RustWriter, inMemoryWriter: RustWriter) {
249+
// Traverse all descendent inline modules and render them.
250+
inlineModuleWriters[inMemoryWriter]?.forEach {
251+
writeDocs(it.inlineModule)
143252

144-
inlineModuleWriters.get(inMemoryWriter)?.forEach {
145-
writeDocs(it.inlineModule, it.writer)
146-
writer.withInlineModule(it.inlineModule) {
253+
topLevelWriter.withInlineModule(it.inlineModule) {
254+
writeInlineCode(this, it.writer.toString())
147255
renderDescendents(this, it.writer)
148256
}
149-
it.writer.dependencies.forEach { dep -> writer.addDependency(dep) }
257+
258+
// Add dependencies introduced by the inline module to the
259+
it.writer.dependencies.forEach { dep -> topLevelWriter.addDependency(dep) }
150260
}
151261
}
152262

153263
// Go over all the top level modules, create an `inlineModule` on the `RustWriter`
154264
// and call the descendent hierarchy renderer using the `inlineModule::RustWriter`
155-
topLevelModuleWriters.forEach { (outerWriter, list) ->
156-
list.forEach {
157-
writeDocs(it.inlineModule, it.writer)
158-
outerWriter.withInlineModule(it.inlineModule) {
159-
renderDescendents(this, it.writer)
160-
}
161-
it.writer.dependencies.forEach { dep -> outerWriter.addDependency(dep) }
265+
topLevelModuleWriters.forEach {
266+
val inlineModuleWithWriter = inlineModuleWriters[it]
267+
if (inlineModuleWithWriter != null) {
268+
renderDescendents(it, it)
162269
}
163270
}
164271
}
165272

273+
/**
274+
* Given the inline-module returns an existing `RustWriter`, or if that inline module
275+
* has never been registered before then a new `RustWriter` is created and returned.
276+
*/
166277
private fun getWriter(outerWriter: RustWriter, inlineModule: RustModule.LeafModule): RustWriter {
167278
// Is this one of our inner writers?
168279
val nestedModuleWriter = inlineModuleWriters[outerWriter]
169280
if (nestedModuleWriter != null) {
170281
return findOrAddToList(nestedModuleWriter, inlineModule)
171282
}
172283

173-
val existing = topLevelModuleWriters[outerWriter]
174-
return if (existing == null) {
175-
val inlineWriter = createNewInlineModule()
176-
topLevelModuleWriters[outerWriter] = mutableListOf(InlineModuleWithWriter(inlineModule, inlineWriter))
177-
inlineWriter
178-
} else {
179-
return findOrAddToList(existing, inlineModule)
180-
}
284+
val inlineWriters = registerTopMostWriter(outerWriter)
285+
return findOrAddToList(inlineWriters, inlineModule)
181286
}
182287

183-
private fun registerTopMostWriter(outerWriter: RustWriter) {
184-
topLevelModuleWriters.getOrPut(outerWriter) {
185-
mutableListOf()
186-
}
288+
/**
289+
* Records the root of a dependency graph of inline modules.
290+
*/
291+
private fun registerTopMostWriter(outerWriter: RustWriter) : MutableList<InlineModuleWithWriter> {
292+
topLevelModuleWriters.add(outerWriter)
293+
return inlineModuleWriters.getOrPut(outerWriter) { mutableListOf() }
187294
}
188295

296+
/**
297+
* Either gets a new `RustWriter` for the inline module or creates a new one and adds it to
298+
* the list of inline modules.
299+
*/
189300
private fun findOrAddToList(
190301
inlineModuleList: MutableList<InlineModuleWithWriter>,
191302
lookForModule: RustModule.LeafModule
@@ -202,98 +313,9 @@ class InnerModule(private val debugMode : Boolean) {
202313
}
203314
}
204315

205-
private fun writeDocs(innerModule: RustModule.LeafModule, rustWriter: RustWriter) {
316+
private fun writeDocs(innerModule: RustModule.LeafModule) {
206317
docWriters[innerModule]?.forEach{
207318
it()
208319
}
209320
}
210321
}
211-
212-
// A map of RustCrate to InlineModule
213-
private val crateToInlineModule: ConcurrentHashMap<RustCrate, InnerModule> =
214-
ConcurrentHashMap()
215-
private val writerToCrateLookup: ConcurrentHashMap<RustWriter, RustCrate> =
216-
ConcurrentHashMap()
217-
218-
fun RustCrate.initializeInlineModuleWriter(codegenContext: ServerCodegenContext): InnerModule =
219-
crateToInlineModule
220-
.getOrPut(this) { InnerModule(codegenContext.settings.codegenConfig.debugMode) }
221-
222-
fun RustCrate.getInlineModuleWriter() : InnerModule {
223-
return crateToInlineModule.getOrPut(this) { InnerModule(false) }
224-
}
225-
226-
227-
/**
228-
* If the passed in `shape` is a synthetic extracted shape resulting from a constrained struct member,
229-
* the `Writable` is called using the structure's builder module. Otherwise the `Writable` is called
230-
* using the given `module`.
231-
*/
232-
fun RustCrate.withModuleOrWithStructureBuilderModule(
233-
module: RustModule,
234-
shape: Shape,
235-
codegenContext: ServerCodegenContext,
236-
codeWritable: Writable,
237-
) {
238-
// All structure constrained-member-shapes code is generated inside the structure builder's module.
239-
val parentAndInlineModuleInfo =
240-
shape.getParentAndInlineModuleForConstrainedMember(codegenContext.symbolProvider, !codegenContext.settings.codegenConfig.publicConstrainedTypes)
241-
if (parentAndInlineModuleInfo == null) {
242-
this.withModule(module, codeWritable)
243-
} else {
244-
val (parent, inline) = parentAndInlineModuleInfo
245-
val inlineWriter = this.getInlineModuleWriter()
246-
247-
inlineWriter.withInlineModuleHierarchyUsingCrate(this, parent) {
248-
inlineWriter.withInlineModuleHierarchy(this, inline) {
249-
codeWritable(this)
250-
}
251-
}
252-
}
253-
}
254-
255-
/**
256-
* If the passed in `shape` is a synthetic extracted shape resulting from a constrained struct member,
257-
* the `Writable` is called using the structure's builder module. Otherwise the `Writable` is called
258-
* using shape's `module`.
259-
*/
260-
fun RustCrate.useShapeWriterOrUseWithStructureBuilder(
261-
shape: Shape,
262-
codegenContext: ServerCodegenContext,
263-
docWriter: DocWriter? = null,
264-
writable: Writable,
265-
) {
266-
// All structure constrained-member-shapes code is generated inside the structure builder's module.
267-
val parentAndInlineModuleInfo =
268-
shape.getParentAndInlineModuleForConstrainedMember(codegenContext.symbolProvider, !codegenContext.settings.codegenConfig.publicConstrainedTypes)
269-
if (parentAndInlineModuleInfo == null) {
270-
docWriter?.invoke()
271-
this.useShapeWriter(shape, writable)
272-
} else {
273-
val (parent, inline) = parentAndInlineModuleInfo
274-
val inlineWriter = this.getInlineModuleWriter()
275-
276-
inlineWriter.withInlineModuleHierarchyUsingCrate(this, parent) {
277-
inlineWriter.withInlineModuleHierarchy(this, inline) {
278-
writable(this)
279-
}
280-
}
281-
}
282-
}
283-
284-
/**
285-
* Given a `RustWriter` calls the `Writable` using a `RustWriter` for the `inlineModule`
286-
*/
287-
fun RustCrate.withInMemoryInlineModule(
288-
outerWriter: RustWriter,
289-
inlineModule: RustModule.LeafModule,
290-
docWriter: DocWriter?,
291-
codeWritable: Writable,
292-
) {
293-
check(inlineModule.isInline()) {
294-
"module has to be an inline module for it to be used with the InlineModuleWriter"
295-
}
296-
this.getInlineModuleWriter().withInlineModuleHierarchy(outerWriter, inlineModule, docWriter) {
297-
codeWritable(this)
298-
}
299-
}

codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ open class ServerCodegenVisitor(
216216
}
217217
}
218218

219-
rustCrate.initializeInlineModuleWriter(codegenContext)
219+
rustCrate.initializeInlineModuleWriter(codegenContext.settings.codegenConfig.debugMode)
220220

221221
val serviceShapes = DirectedWalker(model).walkShapes(service)
222222
serviceShapes.forEach { it.accept(this) }

0 commit comments

Comments
 (0)