@@ -12,6 +12,21 @@ import java.util.concurrent.ConcurrentHashMap
1212typealias DocWriter = () -> Any
1313typealias 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+
26115fun 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+ */
35126private 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+
37134class 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- }
0 commit comments