idlize

Форк
0
/
SerializerPrinter.ts 
220 строк · 9.9 Кб
1
/*
2
 * Copyright (c) 2024 Huawei Device Co., Ltd.
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15

16
import * as ts from 'typescript'
17
import { Language } from "../../util";
18
import { DeclarationTable, DeclarationTarget, PrimitiveType } from "../DeclarationTable";
19
import { LanguageWriter, Method, NamedMethodSignature, Type } from "../LanguageWriters";
20
import { PeerGeneratorConfig } from '../PeerGeneratorConfig';
21
import { checkDeclarationTargetMaterialized } from '../Materialized';
22
import { ImportsCollector } from '../ImportsCollector';
23
import { PeerLibrary } from '../PeerLibrary';
24
import { collectDtsImports } from '../DtsImportsGenerator';
25

26
function collectAllInterfacesImports(library: PeerLibrary, imports: ImportsCollector) {
27
    for (const file of library.files)
28
        file.importFeatures.forEach(it => imports.addFeature(it.feature, it.module))
29
}
30

31
function printSerializerImports(library: PeerLibrary, writer: LanguageWriter) {
32
    if (writer.language === Language.TS) {
33
        const collector = new ImportsCollector()
34
        collectAllInterfacesImports(library, collector)
35
        collector.print(writer)
36
    } else if (writer.language === Language.ARKTS) {
37
        writer.print(collectDtsImports().trim())
38
    }
39
}
40

41
function canSerializeTarget(declaration: ts.ClassDeclaration | ts.InterfaceDeclaration): boolean {
42
    // we can not generate serializer/deserializer for targets, where
43
    // type parameters are in signature and some of this parameters has not
44
    // default value. At all we should not generate even classes with default values,
45
    // but they are at least compilable.
46
    // See class TransitionEffect declared at common.d.ts and used at CommonMethod.transition
47
    return (declaration.typeParameters ?? []).every(it => {
48
        return it.default !== undefined
49
    })
50
}
51

52
function ignoreSerializeTarget(table: DeclarationTable, target: DeclarationTarget): target is PrimitiveType | ts.EnumDeclaration {
53
    const name = table.computeTargetName(target, false)
54
    if (PeerGeneratorConfig.ignoreSerialization.includes(name)) return true
55
    if (target instanceof PrimitiveType) return true
56
    if (ts.isEnumDeclaration(target)) return true
57
    if (ts.isFunctionTypeNode(target)) return true
58
    if (ts.isImportTypeNode(target)) return true
59
    if (ts.isTemplateLiteralTypeNode(target)) return true
60
    if (checkDeclarationTargetMaterialized(target)) return true
61
    return false
62
}
63

64
class SerializerPrinter {
65
    constructor(
66
        private readonly library: PeerLibrary,
67
        private readonly writer: LanguageWriter,
68
    ) {}
69

70
    private get table(): DeclarationTable {
71
        return this.library.declarationTable
72
    }
73

74
    private translateSerializerType(name: string, target: DeclarationTarget): string {
75
        if (target instanceof PrimitiveType) throw new Error("Unexpected")
76
        if (ts.isInterfaceDeclaration(target) && target.typeParameters != undefined) {
77
            if (target.typeParameters.length != 1) throw new Error("Unexpected")
78
            return `${name}<object>`
79
        } else {
80
            return name
81
        }
82
    }
83

84
    private generateSerializer(target: ts.ClassDeclaration | ts.InterfaceDeclaration) {
85
        const name = this.table.computeTargetName(target, false)
86
        this.table.setCurrentContext(`write${name}()`)
87

88
        this.writer.writeMethodImplementation(
89
            new Method(`write${name}`,
90
                new NamedMethodSignature(Type.Void, [new Type(this.translateSerializerType(name, target))], ["value"])),
91
            writer => {
92
                writer.writeStatement(
93
                    writer.makeAssign("valueSerializer", new Type(writer.makeRef("Serializer")), writer.makeThis(), true, false))
94
                let struct = this.table.targetStruct(target)
95
                struct.getFields().forEach(it => {
96
                    let field = `value_${it.name}`
97
                    writer.writeStatement(writer.makeAssign(field, undefined, writer.makeString(`value.${it.name}`), true))
98
                    let typeConvertor = this.table.typeConvertor(`value`, it.type!, it.optional)
99
                    typeConvertor.convertorSerialize(`value`, field, writer)
100
                })
101
            })
102
        this.table.setCurrentContext(undefined)
103
    }
104

105
    print() {
106
        const className = "Serializer"
107
        const superName = `${className}Base`
108
        let ctorSignature: NamedMethodSignature | undefined = undefined
109
        switch (this.writer.language) {
110
            case Language.ARKTS:
111
                ctorSignature = new NamedMethodSignature(Type.Void, [], [])
112
                break;
113
            case Language.CPP:
114
                ctorSignature = new NamedMethodSignature(Type.Void, [new Type("uint8_t*")], ["data"])
115
                break;
116
            case Language.JAVA:
117
                ctorSignature = new NamedMethodSignature(Type.Void, [], [])
118
                break;
119
            }
120
        let seenNames = new Set<string>()
121
        printSerializerImports(this.library, this.writer)
122
        this.writer.writeClass(className, writer => {
123
            if (ctorSignature) {
124
                const ctorMethod = new Method(superName, ctorSignature)
125
                writer.writeConstructorImplementation(className, ctorSignature, writer => {}, ctorMethod)
126
            }
127
            for (let declaration of this.table.orderedDependenciesToGenerate) {
128
                if (ignoreSerializeTarget(this.table, declaration))
129
                    continue
130
                let name = this.table.computeTargetName(declaration, false)
131
                if (seenNames.has(name)) continue
132
                seenNames.add(name)
133
                if (ts.isInterfaceDeclaration(declaration) || ts.isClassDeclaration(declaration))
134
                    if (canSerializeTarget(declaration))
135
                        this.generateSerializer(declaration)
136
            }
137
            if (this.writer.language == Language.JAVA) {
138
                // TODO: somewhat ugly.
139
                this.writer.print(`static Serializer createSerializer() { return new Serializer(); }`)
140
            }
141
        }, superName)
142
    }
143
}
144

145
class DeserializerPrinter {
146
    constructor(
147
        private readonly library: PeerLibrary,
148
        private readonly writer: LanguageWriter,
149
    ) {}
150

151
    private get table(): DeclarationTable {
152
        return this.library.declarationTable
153
    }
154

155
    private generateDeserializer(target: ts.ClassDeclaration | ts.InterfaceDeclaration) {
156
        const name = this.table.computeTargetName(target, false)
157
        this.table.setCurrentContext(`read${name}()`)
158
        const type = new Type(name)
159
        this.writer.writeMethodImplementation(new Method(`read${name}`, new NamedMethodSignature(type, [], [])), writer => {
160
            writer.writeStatement(
161
                writer.makeAssign("valueDeserializer", new Type(writer.makeRef("Deserializer")), writer.makeThis(), true, false))
162
            // using list initialization to prevent uninitialized value errors
163
            writer.writeStatement(writer.makeObjectDeclare("value", type, this.table.targetStruct(target).getFields()))
164
            if (ts.isInterfaceDeclaration(target) || ts.isClassDeclaration(target)) {
165
                let struct = this.table.targetStruct(target)
166
                struct.getFields().forEach(it => {
167
                    let typeConvertor = this.table.typeConvertor(`value`, it.type!, it.optional)
168
                    writer.writeStatement(typeConvertor.convertorDeserialize(`value`, `value.${it.name}`, writer))
169
                })
170
            } else {
171
                if (writer.language === Language.CPP) {
172
                    let typeConvertor = this.table.typeConvertor("value", target, false)
173
                    writer.writeStatement(typeConvertor.convertorDeserialize(`value`, `value`, writer))
174
                }
175
            }
176
            writer.writeStatement(writer.makeReturn(
177
                writer.makeCast(writer.makeString("value"), new Type(name))))
178
        })
179
        this.table.setCurrentContext(undefined)
180
    }
181

182
    print() {
183
        const className = "Deserializer"
184
        const superName = `${className}Base`
185
        let ctorSignature = this.writer.language == Language.CPP
186
            ? new NamedMethodSignature(Type.Void, [new Type("uint8_t*"), Type.Int32], ["data", "length"])
187
            : undefined
188
        printSerializerImports(this.library, this.writer)
189
        this.writer.writeClass(className, writer => {
190
            if (ctorSignature) {
191
                const ctorMethod = new Method(`${className}Base`, ctorSignature)
192
                writer.writeConstructorImplementation(className, ctorSignature, writer => {}, ctorMethod)
193
            }
194
            const seenNames = new Set<string>()
195
            for (let declaration of this.table.orderedDependenciesToGenerate) {
196
                if (ignoreSerializeTarget(this.table, declaration))
197
                    continue
198

199
                let name = this.table.computeTargetName(declaration, false)
200
                if (seenNames.has(name)) continue
201
                seenNames.add(name)
202

203
                if (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) {
204
                    if (canSerializeTarget(declaration))
205
                        this.generateDeserializer(declaration)
206
                }
207
            }
208
        }, superName)
209
    }
210
}
211

212
export function writeSerializer(library: PeerLibrary, writer: LanguageWriter) {
213
    const printer = new SerializerPrinter(library, writer)
214
    printer.print()
215
}
216

217
export function writeDeserializer(library: PeerLibrary, writer: LanguageWriter) {
218
    const printer = new DeserializerPrinter(library, writer)
219
    printer.print()
220
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.