generateSerializers method
String
generateSerializers(
- Map serializers
)
Implementation
String generateSerializers(Map serializers) {
final library = Library((b) {
final serializerReader = MapReader(serializers);
for (final key in serializers.keys) {
final class_ = Class((b) {
final className = '$key';
b.name = className;
b.fields.add(Field((b) {
b.static = true;
b.type = Reference('Map<Type, int>');
b.name = '_types';
b.modifier = FieldModifier.final$;
b.assignment = Code('_generateTypes()');
}));
b.methods.add(Method((b) {
b.static = true;
b.returns = Reference('T');
b.name = 'deserialize';
b.types.add(Reference('T'));
b.requiredParameters.add(Parameter((b) {
b.name = 'value';
b.type = Reference('Object?');
}));
final types = serializerReader.read<Map>('$className.types');
final cases = <String>[];
final keys = types.keys.toList();
for (var i = 0; i < keys.length; i++) {
final key = keys[i];
final typeName = '$key';
cases.add('case $i:');
final deserialize = serializerReader.tryRead<String>(
'$className.types.$typeName.deserialize', false);
if (deserialize == null) {
cases.add(
'result = value == null ? null : $typeName.fromJson(value as Map);');
} else {
cases.add(deserialize);
}
cases.add('break;');
}
const template = r'''
final id = _types[T];
dynamic result;
switch (id) {
{{cases}}
default:
throw StateError('Unable to deserialize type $T');
}
if (result is T) {
return result;
}
throw StateError("Unable to cast '${result.runtimeType}' value to type $T");''';
final values = {
'cases': cases.join('\n'),
};
b.body = Code(render(template, values));
}));
b.methods.add(Method((b) {
b.static = true;
b.returns = Reference('Object?');
b.name = 'serialize';
b.types.add(Reference('T'));
b.requiredParameters.add(Parameter((b) {
b.name = 'value';
b.type = Reference('T');
}));
final types = serializerReader.read<Map>('$className.types');
final cases = <String>[];
final keys = types.keys.toList();
for (var i = 0; i < keys.length; i++) {
final key = keys[i];
final typeName = '$key';
cases.add('case $i:');
final serialize = serializerReader.tryRead<String>(
'$className.types.$typeName.serialize', false);
if (serialize == null) {
cases.add(
'result = value == null ? null : (value as $typeName).toJson();');
} else {
cases.add(serialize);
}
cases.add('break;');
}
const template = r'''
final id = _types[T];
Object? result;
switch (id) {
{{cases}}
default:
throw StateError('Unable to serialize type $T');
}
return result;''';
final values = {
'cases': cases.join('\n'),
};
b.body = Code(render(template, values));
}));
b.methods.add(Method((b) {
b.static = true;
b.name = '_generateTypes';
b.returns = Reference('Map<Type, int>');
final code = <String>[];
final types = serializerReader.read<Map>('$className.types');
final keys = types.keys.toList();
for (var i = 0; i < keys.length; i++) {
final key = keys[i];
final typeName = '$key';
final type = _parseType(typeName);
if (type.hasSuffix) {
throw StateError(
"The serializer requires the type '$type' to be specified without a suffix ($className.types.$key)");
}
if (type.arguments.isNotEmpty) {
throw StateError(
"The serializer does not support the type '$type' with type parameters ($className.types.$key)");
}
code.add('addType<$typeName>($i);');
code.add('addType<$typeName?>($i);');
}
const template = r'''
final result = <Type, int>{};
void addType<T>(int id) {
result[T] = id;
}
{{code}}
return result;''';
final values = {
'code': code.join('\n'),
};
b.body = Code(render(template, values));
}));
});
b.body.add(class_);
}
});
final emitter = DartEmitter();
final result = library.accept(emitter).toString();
return result;
}