make tryGet* safer
* check casts (for list and map) at cast time by recreating the list/map
instead of throwing on access.
* type warnings work now slightly differently:
* when we expect nullable fields to be actually null within normal
operation you can explicitly set the tryGet type param to an
optional type and mute the warning. Otherwise it'll warn that something
is null which we expect to something else.
This commit is contained in:
parent
c73ea67bcd
commit
0b8e3f3071
|
|
@ -47,8 +47,8 @@ class RoomEncryptedContent {
|
||||||
RoomEncryptedContent.fromJson(Map<String, dynamic> json)
|
RoomEncryptedContent.fromJson(Map<String, dynamic> json)
|
||||||
: algorithm = json.tryGet('algorithm') ?? '',
|
: algorithm = json.tryGet('algorithm') ?? '',
|
||||||
senderKey = json.tryGet('sender_key') ?? '',
|
senderKey = json.tryGet('sender_key') ?? '',
|
||||||
deviceId = json.tryGet('device_id'),
|
deviceId = json.tryGet<String?>('device_id'),
|
||||||
sessionId = json.tryGet('session_id'),
|
sessionId = json.tryGet<String?>('session_id'),
|
||||||
ciphertextMegolm = json.silentTryGet('ciphertext'),
|
ciphertextMegolm = json.silentTryGet('ciphertext'),
|
||||||
// filter out invalid/incomplete CiphertextInfos
|
// filter out invalid/incomplete CiphertextInfos
|
||||||
ciphertextOlm = json
|
ciphertextOlm = json
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,16 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'dart:core';
|
||||||
|
|
||||||
import 'logs.dart';
|
import 'logs.dart';
|
||||||
|
|
||||||
extension TryGetMapExtension on Map<String, dynamic> {
|
extension TryGetMapExtension on Map<String, dynamic> {
|
||||||
T? tryGet<T extends Object>(String key) {
|
T? tryGet<T extends Object?>(String key) {
|
||||||
final value = this[key];
|
final Object? value = this[key];
|
||||||
if (value != null && !(value is T)) {
|
if (value is! T) {
|
||||||
Logs().w(
|
Logs().w(
|
||||||
'Expected "${T.runtimeType}" in event content for the Key "$key" but got "${value.runtimeType}".',
|
'Expected "$T" in event content for the Key "$key" but got "${value.runtimeType}".');
|
||||||
StackTrace.current);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
|
@ -37,43 +38,45 @@ extension TryGetMapExtension on Map<String, dynamic> {
|
||||||
|
|
||||||
/// Same as tryGet but without logging any warnings.
|
/// Same as tryGet but without logging any warnings.
|
||||||
/// This is helpful if you have a field that can mean multiple things on purpose.
|
/// This is helpful if you have a field that can mean multiple things on purpose.
|
||||||
T? silentTryGet<T extends Object>(String key) {
|
T? silentTryGet<T extends Object?>(String key) {
|
||||||
final value = this[key];
|
final Object? value = this[key];
|
||||||
if (value != null && !(value is T)) {
|
if (value is! T) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T>? tryGetList<T>(String key) {
|
List<T>? tryGetList<T>(String key) {
|
||||||
final value = this[key];
|
final Object? value = this[key];
|
||||||
if (value != null && !(value is List)) {
|
if (value is! List) {
|
||||||
Logs().w(
|
Logs().w(
|
||||||
'Expected "List<${T.runtimeType}>" in event content for the key "$key" but got "${value.runtimeType}".',
|
'Expected "List<$T>" in event content for the key "$key" but got "${value.runtimeType}".',
|
||||||
StackTrace.current);
|
StackTrace.current);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (value as List).cast<T>();
|
// copy entries to ensure type check failures here and not an access
|
||||||
|
return value.cast<T>().toList();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
Logs().w(
|
Logs()
|
||||||
'Unable to create "List<${T.runtimeType}>" in event content for the key "$key"');
|
.w('Unable to create "List<$T>" in event content for the key "$key"');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<A, B>? tryGetMap<A, B>(String key) {
|
Map<A, B>? tryGetMap<A, B>(String key) {
|
||||||
final value = this[key];
|
final Object? value = this[key];
|
||||||
if (value != null && !(value is Map)) {
|
if (value is! Map) {
|
||||||
Logs().w(
|
Logs().w(
|
||||||
'Expected "Map<${A.runtimeType},${B.runtimeType}>" in event content for the key "$key" but got "${value.runtimeType}".');
|
'Expected "Map<$A,$B>" in event content for the key "$key" but got "${value.runtimeType}".');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (value as Map).cast<A, B>();
|
// copy map to ensure type check failures here and not an access
|
||||||
|
return Map.from(value.cast<A, B>());
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
Logs().w(
|
Logs().w(
|
||||||
'Unable to create "Map<${A.runtimeType},${B.runtimeType}>" in event content for the key "$key"');
|
'Unable to create "Map<$A,$B>" in event content for the key "$key"');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue