Skip to content
This repository was archived by the owner on May 25, 2022. It is now read-only.

Commit 56f5fda

Browse files
committed
Merge pull request #16 from davidmorgan/fix-comments
Stopped falling back to <Object> for collection generic types. Fixes for review comments.
2 parents 6d04dbe + a4ae517 commit 56f5fda

29 files changed

+568
-367
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 0.0.3
4+
5+
- Stop falling back to "<Object>" for collection type parameters.
6+
- Extend code generation to add the builders needed for collections.
7+
- Differentiate Object from unspecified.
8+
39
## 0.0.2
410

511
- Rewrite to fully use static type information.

built_json/lib/built_json.dart

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,34 +37,37 @@ abstract class Serializers {
3737
///
3838
/// A [Serializer] must have been provided for every the object uses.
3939
///
40-
/// Types that are known statically can be provided via [genericType]. This
40+
/// Types that are known statically can be provided via [specifiedType]. This
4141
/// will reduce the amount of data needed on the wire. The exact same
42-
/// [genericType] will be needed to deserialize.
42+
/// [specifiedType] will be needed to deserialize.
4343
///
4444
/// Create one using [SerializersBuilder].
4545
///
4646
/// TODO(davidmorgan): document the wire format.
4747
Object serialize(Object object,
48-
{GenericType genericType: const GenericType()});
48+
{FullType specifiedType: FullType.unspecified});
4949

5050
/// Deserializes [serialized].
5151
///
5252
/// A [Serializer] must have been provided for every the object uses.
5353
///
54-
/// If [serialized] was produced by calling [serialize] with [genericType],
55-
/// the exact same [genericType] must be provided to deserialize.
54+
/// If [serialized] was produced by calling [serialize] with [specifiedType],
55+
/// the exact same [specifiedType] must be provided to deserialize.
5656
Object deserialize(Object serialized,
57-
{GenericType genericType: const GenericType()});
57+
{FullType specifiedType: FullType.unspecified});
5858

59-
/// Creates a new builder for the type represented by [genericType].
59+
/// Creates a new builder for the type represented by [fullType].
6060
///
61-
/// For example, if [genericType] is `BuiltList<int, String>`, returns a
61+
/// For example, if [fullType] is `BuiltList<int, String>`, returns a
6262
/// `ListBuilder<int, String>`. This helps serializers to instantiate with
6363
/// correct generic type parameters.
6464
///
6565
/// May return null if no matching builder factory has been added. In this
66-
/// case the serializer should fall back to `Object`.
67-
Object newBuilder(GenericType genericType);
66+
/// case the serializer should throw a [StateError].
67+
Object newBuilder(FullType fullType);
68+
69+
/// Whether a builder for [fullType] is available via [newBuilder].
70+
bool hasBuilder(FullType fullType);
6871

6972
SerializersBuilder toBuilder();
7073
}
@@ -75,22 +78,35 @@ abstract class SerializersBuilder {
7578

7679
void add(Serializer serializer);
7780

78-
void addBuilderFactory(GenericType genericType, Function function);
81+
void addBuilderFactory(FullType specifiedType, Function function);
7982

8083
Serializers build();
8184
}
8285

83-
/// A tree of [Type] instances.
84-
class GenericType {
86+
/// A [Type] with, optionally, [FullType] generic type parameters.
87+
///
88+
/// May also be [unspecified], indicating that no type information is
89+
/// available.
90+
class FullType {
91+
// An unspecified type.
92+
static const unspecified = const FullType(null);
93+
8594
/// The root of the type.
8695
final Type root;
8796

8897
/// Type parameters of the type.
89-
final List<GenericType> parameters;
98+
final List<FullType> parameters;
99+
100+
const FullType(this.root, [this.parameters = const []]);
90101

91-
const GenericType([this.root = Object, this.parameters = const []]);
102+
bool get isUnspecified => identical(root, null);
92103

93-
bool get isObject => root == Object;
104+
@override
105+
String toString() => isUnspecified
106+
? 'unspecified'
107+
: parameters.isEmpty
108+
? root.toString()
109+
: '${root.toString()}<${parameters.join(", ")}>';
94110
}
95111

96112
/// Serializes a single type.
@@ -118,16 +134,16 @@ abstract class Serializer<T> {
118134
/// Serializes [object].
119135
///
120136
/// Use [serializers] as needed for nested serialization. Information about
121-
/// the type being serialized is provided in [genericType].
137+
/// the type being serialized is provided in [specifiedType].
122138
///
123139
/// TODO(davidmorgan): document the wire format.
124140
Object serialize(Serializers serializers, T object,
125-
{GenericType genericType: const GenericType()});
141+
{FullType specifiedType: FullType.unspecified});
126142

127143
/// Deserializes [serialized].
128144
///
129145
/// Use [serializers] as needed for nested deserialization. Information about
130-
/// the type being deserialized is provided in [genericType].
146+
/// the type being deserialized is provided in [specifiedType].
131147
T deserialize(Serializers serializers, Object serialized,
132-
{GenericType genericType: const GenericType()});
148+
{FullType specifiedType: FullType.unspecified});
133149
}

built_json/lib/src/bool_serializer.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ class BoolSerializer implements Serializer<bool> {
1111
final String wireName = 'bool';
1212

1313
@override
14-
Object serialize(Serializers serializers, bool object,
15-
{GenericType genericType: const GenericType()}) {
16-
return object;
14+
Object serialize(Serializers serializers, bool boolean,
15+
{FullType specifiedType: FullType.unspecified}) {
16+
return boolean;
1717
}
1818

1919
@override
20-
bool deserialize(Serializers serializers, Object object,
21-
{GenericType genericType: const GenericType()}) {
22-
return object as bool;
20+
bool deserialize(Serializers serializers, Object serialized,
21+
{FullType specifiedType: FullType.unspecified}) {
22+
return serialized as bool;
2323
}
2424
}

built_json/lib/src/built_json_serializers.dart

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ class BuiltJsonSerializers implements Serializers {
1010
final BuiltMap<Type, Serializer> _typeToSerializer;
1111
final BuiltMap<String, Serializer> _wireNameToSerializer;
1212
final BuiltMap<String, Serializer> _typeNameToSerializer;
13-
final BuiltMap<GenericType, Function> _builderFactories;
13+
final BuiltMap<FullType, Function> _builderFactories;
1414

1515
BuiltJsonSerializers._(this._typeToSerializer, this._wireNameToSerializer,
1616
this._typeNameToSerializer, this._builderFactories);
1717

1818
@override
1919
Object serialize(Object object,
20-
{GenericType genericType: const GenericType()}) {
21-
if (genericType.isObject) {
20+
{FullType specifiedType: FullType.unspecified}) {
21+
if (specifiedType.isUnspecified) {
2222
final serializer = _getSerializerByType(object.runtimeType);
2323
if (serializer == null) throw new StateError(
2424
"No serializer for '${object.runtimeType}'.");
@@ -31,19 +31,19 @@ class BuiltJsonSerializers implements Serializers {
3131
return <Object>[serializer.wireName, serialized];
3232
}
3333
} else {
34-
final serializer = _getSerializerByType(genericType.root);
34+
final serializer = _getSerializerByType(specifiedType.root);
3535
if (serializer == null) throw new StateError(
36-
"No serializer for '${genericType.root}'.");
36+
"No serializer for '${specifiedType.root}'.");
3737
final result =
38-
serializer.serialize(this, object, genericType: genericType);
38+
serializer.serialize(this, object, specifiedType: specifiedType);
3939
return serializer.structured ? (result as Iterable).toList() : result;
4040
}
4141
}
4242

4343
@override
4444
Object deserialize(Object object,
45-
{GenericType genericType: const GenericType()}) {
46-
if (genericType.isObject) {
45+
{FullType specifiedType: FullType.unspecified}) {
46+
if (specifiedType.isUnspecified) {
4747
final wireName = (object as List).first;
4848

4949
final serializer = _wireNameToSerializer[wireName];
@@ -55,19 +55,24 @@ class BuiltJsonSerializers implements Serializers {
5555
: (object as List)[1];
5656
return serializer.deserialize(this, json);
5757
} else {
58-
final serializer = _getSerializerByType(genericType.root);
58+
final serializer = _getSerializerByType(specifiedType.root);
5959
if (serializer == null) throw new StateError(
60-
"No serializer for '${genericType.root}'.");
61-
return serializer.deserialize(this, object, genericType: genericType);
60+
"No serializer for '${specifiedType.root}'.");
61+
return serializer.deserialize(this, object, specifiedType: specifiedType);
6262
}
6363
}
6464

6565
@override
66-
Object newBuilder(types) {
67-
final builderFactory = _builderFactories[types];
66+
Object newBuilder(FullType fullType) {
67+
final builderFactory = _builderFactories[fullType];
6868
return builderFactory == null ? null : builderFactory();
6969
}
7070

71+
@override
72+
bool hasBuilder(FullType fullType) {
73+
return _builderFactories.containsKey(fullType);
74+
}
75+
7176
@override
7277
SerializersBuilder toBuilder() {
7378
return new BuiltJsonSerializersBuilder._(
@@ -91,8 +96,8 @@ class BuiltJsonSerializersBuilder implements SerializersBuilder {
9196
MapBuilder<String, Serializer> _typeNameToSerializer =
9297
new MapBuilder<String, Serializer>();
9398

94-
MapBuilder<GenericType, Function> _builderFactories =
95-
new MapBuilder<GenericType, Function>();
99+
MapBuilder<FullType, Function> _builderFactories =
100+
new MapBuilder<FullType, Function>();
96101

97102
BuiltJsonSerializersBuilder();
98103

@@ -110,7 +115,7 @@ class BuiltJsonSerializersBuilder implements SerializersBuilder {
110115
}
111116
}
112117

113-
void addBuilderFactory(GenericType types, Function function) {
118+
void addBuilderFactory(FullType types, Function function) {
114119
_builderFactories[types] = function;
115120
}
116121

built_json/lib/src/built_list_serializer.dart

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,43 @@ class BuiltListSerializer implements Serializer<BuiltList> {
1111
final String wireName = 'list';
1212

1313
@override
14-
Object serialize(Serializers serializers, BuiltList object,
15-
{GenericType genericType: const GenericType()}) {
16-
final valueGenericType = genericType.parameters.isEmpty
17-
? const GenericType()
18-
: genericType.parameters[0];
19-
20-
return object.map(
21-
(item) => serializers.serialize(item, genericType: valueGenericType));
14+
Object serialize(Serializers serializers, BuiltList builtList,
15+
{FullType specifiedType: FullType.unspecified}) {
16+
final isUnderspecified =
17+
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
18+
19+
final elementType = specifiedType.parameters.isEmpty
20+
? FullType.unspecified
21+
: specifiedType.parameters[0];
22+
23+
if (!isUnderspecified && !serializers.hasBuilder(specifiedType)) {
24+
throw new StateError(
25+
'No builder for $specifiedType, cannot serialize.');
26+
}
27+
28+
return builtList.map(
29+
(item) => serializers.serialize(item, specifiedType: elementType));
2230
}
2331

2432
@override
25-
BuiltList deserialize(Serializers serializers, Object object,
26-
{GenericType genericType: const GenericType()}) {
27-
final valueGenericType = genericType.parameters.isEmpty
28-
? const GenericType()
29-
: genericType.parameters[0];
30-
31-
final result = serializers.newBuilder(genericType) as ListBuilder ??
32-
new ListBuilder<Object>();
33-
result.addAll((object as Iterable).map((item) =>
34-
serializers.deserialize(item, genericType: valueGenericType)));
33+
BuiltList deserialize(Serializers serializers, Object serialized,
34+
{FullType specifiedType: FullType.unspecified}) {
35+
final isUnderspecified =
36+
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
37+
38+
final elementType = specifiedType.parameters.isEmpty
39+
? FullType.unspecified
40+
: specifiedType.parameters[0];
41+
42+
final result = isUnderspecified
43+
? new ListBuilder<Object>()
44+
: serializers.newBuilder(specifiedType) as ListBuilder;
45+
if (result == null) {
46+
throw new StateError(
47+
'No builder for $specifiedType, cannot deserialize.');
48+
}
49+
result.addAll((serialized as Iterable).map((item) =>
50+
serializers.deserialize(item, specifiedType: elementType)));
3551
return result.build();
3652
}
3753
}

built_json/lib/src/built_map_serializer.dart

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,61 @@ class BuiltMapSerializer implements Serializer<BuiltMap> {
1111
final String wireName = 'map';
1212

1313
@override
14-
Object serialize(Serializers serializers, BuiltMap object,
15-
{GenericType genericType: const GenericType()}) {
16-
final keyTypes = genericType.parameters.isEmpty
17-
? const GenericType()
18-
: genericType.parameters[0];
19-
final valueTypes = genericType.parameters.isEmpty
20-
? const GenericType()
21-
: genericType.parameters[1];
14+
Object serialize(Serializers serializers, BuiltMap builtMap,
15+
{FullType specifiedType: FullType.unspecified}) {
16+
final isUnderspecified =
17+
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
18+
19+
final keyType = specifiedType.parameters.isEmpty
20+
? FullType.unspecified
21+
: specifiedType.parameters[0];
22+
final valueType = specifiedType.parameters.isEmpty
23+
? FullType.unspecified
24+
: specifiedType.parameters[1];
25+
26+
if (!isUnderspecified && !serializers.hasBuilder(specifiedType)) {
27+
throw new StateError('No builder for $specifiedType, cannot serialize.');
28+
}
2229

2330
final result = <Object>[];
24-
for (final key in object.keys) {
25-
result.add(serializers.serialize(key, genericType: keyTypes));
26-
final value = object[key];
27-
result.add(serializers.serialize(value, genericType: valueTypes));
31+
for (final key in builtMap.keys) {
32+
result.add(serializers.serialize(key, specifiedType: keyType));
33+
final value = builtMap[key];
34+
result.add(serializers.serialize(value, specifiedType: valueType));
2835
}
2936
return result;
3037
}
3138

3239
@override
33-
BuiltMap deserialize(Serializers serializers, Object object,
34-
{GenericType genericType: const GenericType()}) {
35-
final keyTypes = genericType.parameters.isEmpty
36-
? const GenericType()
37-
: genericType.parameters[0];
38-
final valueTypes = genericType.parameters.isEmpty
39-
? const GenericType()
40-
: genericType.parameters[1];
41-
42-
final result = serializers.newBuilder(genericType) as MapBuilder ??
43-
new MapBuilder<Object, Object>();
44-
final list = object as List<Object>;
40+
BuiltMap deserialize(Serializers serializers, Object serialized,
41+
{FullType specifiedType: FullType.unspecified}) {
42+
final isUnderspecified =
43+
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
44+
45+
final keyType = specifiedType.parameters.isEmpty
46+
? FullType.unspecified
47+
: specifiedType.parameters[0];
48+
final valueType = specifiedType.parameters.isEmpty
49+
? FullType.unspecified
50+
: specifiedType.parameters[1];
51+
52+
final result = isUnderspecified
53+
? new MapBuilder<Object, Object>()
54+
: serializers.newBuilder(specifiedType) as MapBuilder;
55+
if (result == null) {
56+
throw new StateError(
57+
'No builder for $specifiedType, cannot deserialize.');
58+
}
59+
final list = serialized as List<Object>;
4560

4661
if (list.length & 1 == 1) {
4762
throw new ArgumentError('odd length');
4863
}
4964

5065
for (int i = 0; i != list.length; i += 2) {
51-
final key = serializers.deserialize(list[i], genericType: keyTypes);
66+
final key = serializers.deserialize(list[i], specifiedType: keyType);
5267
final value =
53-
serializers.deserialize(list[i + 1], genericType: valueTypes);
68+
serializers.deserialize(list[i + 1], specifiedType: valueType);
5469
result[key] = value;
5570
}
5671

0 commit comments

Comments
 (0)