mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Sped up reading with FlutterStandardCodec. (flutter/engine#38327)
* Sped up reading with FlutterStandardCodec. * added missing license diff * put the IsStandardType in the header so it's closer to where it should change * added unittest for subclassing codecs * fixed lints
This commit is contained in:
parent
7f689ccb23
commit
cf3c286780
@ -2417,6 +2417,8 @@ ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCh
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm + ../../../flutter/LICENSE
|
||||
@ -4872,6 +4874,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChan
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm
|
||||
|
||||
@ -47,6 +47,7 @@ source_set("flutter_channels_arc") {
|
||||
"common/framework/Source/FlutterChannels.mm",
|
||||
"common/framework/Source/FlutterCodecs.mm",
|
||||
"common/framework/Source/FlutterStandardCodec.mm",
|
||||
"common/framework/Source/FlutterStandardCodecHelper.c",
|
||||
"common/framework/Source/FlutterStandardCodec_Internal.h",
|
||||
]
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@ source_set("framework_shared") {
|
||||
"framework/Source/FlutterChannels.mm",
|
||||
"framework/Source/FlutterCodecs.mm",
|
||||
"framework/Source/FlutterStandardCodec.mm",
|
||||
"framework/Source/FlutterStandardCodecHelper.c",
|
||||
"framework/Source/FlutterStandardCodec_Internal.h",
|
||||
]
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h"
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
@ -338,30 +339,16 @@ using namespace flutter;
|
||||
}
|
||||
|
||||
- (void)readBytes:(void*)destination length:(NSUInteger)length {
|
||||
_range.length = length;
|
||||
[_data getBytes:destination range:_range];
|
||||
_range.location += _range.length;
|
||||
FlutterStandardCodecHelperReadBytes(&_range.location, length, destination,
|
||||
(__bridge CFDataRef)_data);
|
||||
}
|
||||
|
||||
- (UInt8)readByte {
|
||||
UInt8 value;
|
||||
[self readBytes:&value length:1];
|
||||
return value;
|
||||
return FlutterStandardCodecHelperReadByte(&_range.location, (__bridge CFDataRef)_data);
|
||||
}
|
||||
|
||||
- (UInt32)readSize {
|
||||
UInt8 byte = [self readByte];
|
||||
if (byte < 254) {
|
||||
return (UInt32)byte;
|
||||
} else if (byte == 254) {
|
||||
UInt16 value;
|
||||
[self readBytes:&value length:2];
|
||||
return value;
|
||||
} else {
|
||||
UInt32 value;
|
||||
[self readBytes:&value length:4];
|
||||
return value;
|
||||
}
|
||||
return FlutterStandardCodecHelperReadSize(&_range.location, (__bridge CFDataRef)_data);
|
||||
}
|
||||
|
||||
- (NSData*)readData:(NSUInteger)length {
|
||||
@ -372,86 +359,47 @@ using namespace flutter;
|
||||
}
|
||||
|
||||
- (NSString*)readUTF8 {
|
||||
NSData* bytes = [self readData:[self readSize]];
|
||||
return [[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding];
|
||||
return (__bridge NSString*)FlutterStandardCodecHelperReadUTF8(&_range.location,
|
||||
(__bridge CFDataRef)_data);
|
||||
}
|
||||
|
||||
- (void)readAlignment:(UInt8)alignment {
|
||||
UInt8 mod = _range.location % alignment;
|
||||
if (mod) {
|
||||
_range.location += (alignment - mod);
|
||||
}
|
||||
}
|
||||
|
||||
- (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type {
|
||||
UInt32 elementCount = [self readSize];
|
||||
UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
|
||||
[self readAlignment:elementSize];
|
||||
NSData* data = [self readData:elementCount * elementSize];
|
||||
return [FlutterStandardTypedData typedDataWithData:data type:type];
|
||||
FlutterStandardCodecHelperReadAlignment(&_range.location, alignment);
|
||||
}
|
||||
|
||||
- (nullable id)readValue {
|
||||
return [self readValueOfType:[self readByte]];
|
||||
return (__bridge id)ReadValue((__bridge CFTypeRef)self);
|
||||
}
|
||||
|
||||
static CFTypeRef ReadValue(CFTypeRef user_data) {
|
||||
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
|
||||
uint8_t type = FlutterStandardCodecHelperReadByte(&reader->_range.location,
|
||||
(__bridge CFDataRef)reader->_data);
|
||||
return (__bridge CFTypeRef)[reader readValueOfType:type];
|
||||
}
|
||||
|
||||
static CFTypeRef ReadTypedDataOfType(FlutterStandardField field, CFTypeRef user_data) {
|
||||
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
|
||||
unsigned long* location = &reader->_range.location;
|
||||
CFDataRef data = (__bridge CFDataRef)reader->_data;
|
||||
FlutterStandardDataType type = FlutterStandardDataTypeForField(field);
|
||||
|
||||
UInt64 elementCount = FlutterStandardCodecHelperReadSize(location, data);
|
||||
UInt64 elementSize = elementSizeForFlutterStandardDataType(type);
|
||||
FlutterStandardCodecHelperReadAlignment(location, elementSize);
|
||||
UInt64 length = elementCount * elementSize;
|
||||
NSRange range = NSMakeRange(*location, length);
|
||||
// Note: subdataWithRange performs better than CFDataCreate and
|
||||
// CFDataCreateBytesNoCopy crashes.
|
||||
NSData* bytes = [(__bridge NSData*)data subdataWithRange:range];
|
||||
*location += length;
|
||||
return (__bridge CFTypeRef)[FlutterStandardTypedData typedDataWithData:bytes type:type];
|
||||
}
|
||||
|
||||
- (nullable id)readValueOfType:(UInt8)type {
|
||||
FlutterStandardField field = (FlutterStandardField)type;
|
||||
switch (field) {
|
||||
case FlutterStandardFieldNil:
|
||||
return nil;
|
||||
case FlutterStandardFieldTrue:
|
||||
return @YES;
|
||||
case FlutterStandardFieldFalse:
|
||||
return @NO;
|
||||
case FlutterStandardFieldInt32: {
|
||||
SInt32 value;
|
||||
[self readBytes:&value length:4];
|
||||
return @(value);
|
||||
}
|
||||
case FlutterStandardFieldInt64: {
|
||||
SInt64 value;
|
||||
[self readBytes:&value length:8];
|
||||
return @(value);
|
||||
}
|
||||
case FlutterStandardFieldFloat64: {
|
||||
Float64 value;
|
||||
[self readAlignment:8];
|
||||
[self readBytes:&value length:8];
|
||||
return [NSNumber numberWithDouble:value];
|
||||
}
|
||||
case FlutterStandardFieldIntHex:
|
||||
case FlutterStandardFieldString:
|
||||
return [self readUTF8];
|
||||
case FlutterStandardFieldUInt8Data:
|
||||
case FlutterStandardFieldInt32Data:
|
||||
case FlutterStandardFieldInt64Data:
|
||||
case FlutterStandardFieldFloat32Data:
|
||||
case FlutterStandardFieldFloat64Data:
|
||||
return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
|
||||
case FlutterStandardFieldList: {
|
||||
UInt32 length = [self readSize];
|
||||
NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
|
||||
for (UInt32 i = 0; i < length; i++) {
|
||||
id value = [self readValue];
|
||||
[array addObject:(value == nil ? [NSNull null] : value)];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
case FlutterStandardFieldMap: {
|
||||
UInt32 size = [self readSize];
|
||||
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
|
||||
for (UInt32 i = 0; i < size; i++) {
|
||||
id key = [self readValue];
|
||||
id val = [self readValue];
|
||||
[dict setObject:(val == nil ? [NSNull null] : val)
|
||||
forKey:(key == nil ? [NSNull null] : key)];
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
default:
|
||||
NSAssert(NO, @"Corrupted standard message");
|
||||
}
|
||||
return (__bridge id)FlutterStandardCodecHelperReadValueOfType(
|
||||
&_range.location, (__bridge CFDataRef)_data, type, ReadValue, ReadTypedDataOfType,
|
||||
(__bridge CFTypeRef)self);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@ -0,0 +1,166 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void FlutterStandardCodecHelperReadAlignment(unsigned long* location,
|
||||
uint8_t alignment) {
|
||||
uint8_t mod = *location % alignment;
|
||||
if (mod) {
|
||||
*location += (alignment - mod);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t PeekByte(unsigned long location, CFDataRef data) {
|
||||
uint8_t result;
|
||||
CFRange range = CFRangeMake(location, 1);
|
||||
CFDataGetBytes(data, range, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FlutterStandardCodecHelperReadBytes(unsigned long* location,
|
||||
unsigned long length,
|
||||
void* destination,
|
||||
CFDataRef data) {
|
||||
CFRange range = CFRangeMake(*location, length);
|
||||
CFDataGetBytes(data, range, destination);
|
||||
*location += length;
|
||||
}
|
||||
|
||||
uint8_t FlutterStandardCodecHelperReadByte(unsigned long* location,
|
||||
CFDataRef data) {
|
||||
uint8_t value;
|
||||
FlutterStandardCodecHelperReadBytes(location, 1, &value, data);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t FlutterStandardCodecHelperReadSize(unsigned long* location,
|
||||
CFDataRef data) {
|
||||
uint8_t byte = FlutterStandardCodecHelperReadByte(location, data);
|
||||
if (byte < 254) {
|
||||
return (uint32_t)byte;
|
||||
} else if (byte == 254) {
|
||||
UInt16 value;
|
||||
FlutterStandardCodecHelperReadBytes(location, 2, &value, data);
|
||||
return value;
|
||||
} else {
|
||||
UInt32 value;
|
||||
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static CFDataRef ReadDataNoCopy(unsigned long* location,
|
||||
unsigned long length,
|
||||
CFDataRef data) {
|
||||
CFDataRef result = CFDataCreateWithBytesNoCopy(
|
||||
kCFAllocatorDefault, CFDataGetBytePtr(data) + *location, length,
|
||||
kCFAllocatorNull);
|
||||
*location += length;
|
||||
return CFAutorelease(result);
|
||||
}
|
||||
|
||||
CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long* location,
|
||||
CFDataRef data) {
|
||||
uint32_t size = FlutterStandardCodecHelperReadSize(location, data);
|
||||
CFDataRef bytes = ReadDataNoCopy(location, size, data);
|
||||
CFStringRef result = CFStringCreateFromExternalRepresentation(
|
||||
kCFAllocatorDefault, bytes, kCFStringEncodingUTF8);
|
||||
return CFAutorelease(result);
|
||||
}
|
||||
|
||||
// Peeks ahead to see if we are reading a standard type. If so, recurse
|
||||
// directly to FlutterStandardCodecHelperReadValueOfType, otherwise recurse to
|
||||
// objc.
|
||||
static inline CFTypeRef FastReadValue(
|
||||
unsigned long* location,
|
||||
CFDataRef data,
|
||||
CFTypeRef (*ReadValue)(CFTypeRef),
|
||||
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
|
||||
CFTypeRef user_data) {
|
||||
uint8_t type = PeekByte(*location, data);
|
||||
if (FlutterStandardFieldIsStandardType(type)) {
|
||||
*location += 1;
|
||||
return FlutterStandardCodecHelperReadValueOfType(
|
||||
location, data, type, ReadValue, ReadTypedDataOfType, user_data);
|
||||
} else {
|
||||
return ReadValue(user_data);
|
||||
}
|
||||
}
|
||||
|
||||
CFTypeRef FlutterStandardCodecHelperReadValueOfType(
|
||||
unsigned long* location,
|
||||
CFDataRef data,
|
||||
uint8_t type,
|
||||
CFTypeRef (*ReadValue)(CFTypeRef),
|
||||
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
|
||||
CFTypeRef user_data) {
|
||||
FlutterStandardField field = (FlutterStandardField)type;
|
||||
switch (field) {
|
||||
case FlutterStandardFieldNil:
|
||||
return nil;
|
||||
case FlutterStandardFieldTrue:
|
||||
return kCFBooleanTrue;
|
||||
case FlutterStandardFieldFalse:
|
||||
return kCFBooleanFalse;
|
||||
case FlutterStandardFieldInt32: {
|
||||
int32_t value;
|
||||
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
|
||||
return CFAutorelease(
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value));
|
||||
}
|
||||
case FlutterStandardFieldInt64: {
|
||||
int64_t value;
|
||||
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
|
||||
return CFAutorelease(
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value));
|
||||
}
|
||||
case FlutterStandardFieldFloat64: {
|
||||
Float64 value;
|
||||
FlutterStandardCodecHelperReadAlignment(location, 8);
|
||||
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
|
||||
return CFAutorelease(
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
|
||||
}
|
||||
case FlutterStandardFieldIntHex:
|
||||
case FlutterStandardFieldString:
|
||||
return FlutterStandardCodecHelperReadUTF8(location, data);
|
||||
case FlutterStandardFieldUInt8Data:
|
||||
case FlutterStandardFieldInt32Data:
|
||||
case FlutterStandardFieldInt64Data:
|
||||
case FlutterStandardFieldFloat32Data:
|
||||
case FlutterStandardFieldFloat64Data:
|
||||
return ReadTypedDataOfType(field, user_data);
|
||||
case FlutterStandardFieldList: {
|
||||
UInt32 length = FlutterStandardCodecHelperReadSize(location, data);
|
||||
CFMutableArrayRef array = CFArrayCreateMutable(
|
||||
kCFAllocatorDefault, length, &kCFTypeArrayCallBacks);
|
||||
for (UInt32 i = 0; i < length; i++) {
|
||||
CFTypeRef value = FastReadValue(location, data, ReadValue,
|
||||
ReadTypedDataOfType, user_data);
|
||||
CFArrayAppendValue(array, (value == nil ? kCFNull : value));
|
||||
}
|
||||
return CFAutorelease(array);
|
||||
}
|
||||
case FlutterStandardFieldMap: {
|
||||
UInt32 size = FlutterStandardCodecHelperReadSize(location, data);
|
||||
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault, size, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
for (UInt32 i = 0; i < size; i++) {
|
||||
CFTypeRef key = FastReadValue(location, data, ReadValue,
|
||||
ReadTypedDataOfType, user_data);
|
||||
CFTypeRef val = FastReadValue(location, data, ReadValue,
|
||||
ReadTypedDataOfType, user_data);
|
||||
CFDictionaryAddValue(dict, (key == nil ? kCFNull : key),
|
||||
(val == nil ? kCFNull : val));
|
||||
}
|
||||
return CFAutorelease(dict);
|
||||
}
|
||||
default:
|
||||
// Malformed message.
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_SOURCE_FLUTTERSTANDARDCODECHELPER_H_
|
||||
#define SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_SOURCE_FLUTTERSTANDARDCODECHELPER_H_
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Note: Update FlutterStandardFieldIsStandardType if this changes.
|
||||
typedef enum {
|
||||
FlutterStandardFieldNil,
|
||||
FlutterStandardFieldTrue,
|
||||
FlutterStandardFieldFalse,
|
||||
FlutterStandardFieldInt32,
|
||||
FlutterStandardFieldInt64,
|
||||
FlutterStandardFieldIntHex,
|
||||
FlutterStandardFieldFloat64,
|
||||
FlutterStandardFieldString,
|
||||
FlutterStandardFieldUInt8Data,
|
||||
FlutterStandardFieldInt32Data,
|
||||
FlutterStandardFieldInt64Data,
|
||||
FlutterStandardFieldFloat64Data,
|
||||
FlutterStandardFieldList,
|
||||
FlutterStandardFieldMap,
|
||||
FlutterStandardFieldFloat32Data,
|
||||
} FlutterStandardField;
|
||||
|
||||
static inline bool FlutterStandardFieldIsStandardType(uint8_t field) {
|
||||
return field <= FlutterStandardFieldFloat32Data &&
|
||||
field >= FlutterStandardFieldNil;
|
||||
}
|
||||
|
||||
void FlutterStandardCodecHelperReadAlignment(unsigned long* location,
|
||||
uint8_t alignment);
|
||||
|
||||
void FlutterStandardCodecHelperReadBytes(unsigned long* location,
|
||||
unsigned long length,
|
||||
void* destination,
|
||||
CFDataRef data);
|
||||
|
||||
uint8_t FlutterStandardCodecHelperReadByte(unsigned long* location,
|
||||
CFDataRef data);
|
||||
|
||||
uint32_t FlutterStandardCodecHelperReadSize(unsigned long* location,
|
||||
CFDataRef data);
|
||||
|
||||
CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long* location,
|
||||
CFDataRef data);
|
||||
|
||||
CFTypeRef FlutterStandardCodecHelperReadValueOfType(
|
||||
unsigned long* location,
|
||||
CFDataRef data,
|
||||
uint8_t type,
|
||||
CFTypeRef (*ReadValue)(CFTypeRef),
|
||||
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
|
||||
CFTypeRef user_data);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_SOURCE_FLUTTERSTANDARDCODECHELPER_H_
|
||||
@ -6,27 +6,11 @@
|
||||
#define SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_SOURCE_FLUTTERSTANDARDCODECINTERNAL_H_
|
||||
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, FlutterStandardField) {
|
||||
FlutterStandardFieldNil,
|
||||
FlutterStandardFieldTrue,
|
||||
FlutterStandardFieldFalse,
|
||||
FlutterStandardFieldInt32,
|
||||
FlutterStandardFieldInt64,
|
||||
FlutterStandardFieldIntHex,
|
||||
FlutterStandardFieldFloat64,
|
||||
FlutterStandardFieldString,
|
||||
FlutterStandardFieldUInt8Data,
|
||||
FlutterStandardFieldInt32Data,
|
||||
FlutterStandardFieldInt64Data,
|
||||
FlutterStandardFieldFloat64Data,
|
||||
FlutterStandardFieldList,
|
||||
FlutterStandardFieldMap,
|
||||
FlutterStandardFieldFloat32Data,
|
||||
};
|
||||
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
|
||||
|
||||
namespace flutter {
|
||||
FlutterStandardField FlutterStandardFieldForDataType(FlutterStandardDataType type) {
|
||||
FlutterStandardField FlutterStandardFieldForDataType(
|
||||
FlutterStandardDataType type) {
|
||||
switch (type) {
|
||||
case FlutterStandardDataTypeUInt8:
|
||||
return FlutterStandardFieldUInt8Data;
|
||||
@ -40,7 +24,8 @@ FlutterStandardField FlutterStandardFieldForDataType(FlutterStandardDataType typ
|
||||
return FlutterStandardFieldFloat64Data;
|
||||
}
|
||||
}
|
||||
FlutterStandardDataType FlutterStandardDataTypeForField(FlutterStandardField field) {
|
||||
FlutterStandardDataType FlutterStandardDataTypeForField(
|
||||
FlutterStandardField field) {
|
||||
switch (field) {
|
||||
case FlutterStandardFieldUInt8Data:
|
||||
return FlutterStandardDataTypeUInt8;
|
||||
|
||||
@ -6,6 +6,93 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
FLUTTER_ASSERT_NOT_ARC
|
||||
|
||||
@interface Pair : NSObject
|
||||
@property(atomic, readonly, strong, nullable) NSObject* left;
|
||||
@property(atomic, readonly, strong, nullable) NSObject* right;
|
||||
- (instancetype)initWithLeft:(NSObject*)first right:(NSObject*)right;
|
||||
@end
|
||||
|
||||
@implementation Pair
|
||||
- (instancetype)initWithLeft:(NSObject*)left right:(NSObject*)right {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_left = [left retain];
|
||||
_right = [right retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_left release];
|
||||
[_right release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
static const UInt8 kDATE = 128;
|
||||
static const UInt8 kPAIR = 129;
|
||||
|
||||
@interface ExtendedWriter : FlutterStandardWriter
|
||||
- (void)writeValue:(id)value;
|
||||
@end
|
||||
|
||||
@implementation ExtendedWriter
|
||||
- (void)writeValue:(id)value {
|
||||
if ([value isKindOfClass:[NSDate class]]) {
|
||||
[self writeByte:kDATE];
|
||||
NSDate* date = value;
|
||||
NSTimeInterval time = date.timeIntervalSince1970;
|
||||
SInt64 ms = (SInt64)(time * 1000.0);
|
||||
[self writeBytes:&ms length:8];
|
||||
} else if ([value isKindOfClass:[Pair class]]) {
|
||||
Pair* pair = value;
|
||||
[self writeByte:kPAIR];
|
||||
[self writeValue:pair.left];
|
||||
[self writeValue:pair.right];
|
||||
} else {
|
||||
[super writeValue:value];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ExtendedReader : FlutterStandardReader
|
||||
- (id)readValueOfType:(UInt8)type;
|
||||
@end
|
||||
|
||||
@implementation ExtendedReader
|
||||
- (id)readValueOfType:(UInt8)type {
|
||||
switch (type) {
|
||||
case kDATE: {
|
||||
SInt64 value;
|
||||
[self readBytes:&value length:8];
|
||||
NSTimeInterval time = [NSNumber numberWithLong:value].doubleValue / 1000.0;
|
||||
return [NSDate dateWithTimeIntervalSince1970:time];
|
||||
}
|
||||
case kPAIR: {
|
||||
return [[[Pair alloc] initWithLeft:[self readValue] right:[self readValue]] autorelease];
|
||||
}
|
||||
default:
|
||||
return [super readValueOfType:type];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ExtendedReaderWriter : FlutterStandardReaderWriter
|
||||
- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data;
|
||||
- (FlutterStandardReader*)readerWithData:(NSData*)data;
|
||||
@end
|
||||
|
||||
@implementation ExtendedReaderWriter
|
||||
- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
|
||||
return [[[ExtendedWriter alloc] initWithData:data] autorelease];
|
||||
}
|
||||
- (FlutterStandardReader*)readerWithData:(NSData*)data {
|
||||
return [[[ExtendedReader alloc] initWithData:data] autorelease];
|
||||
}
|
||||
@end
|
||||
|
||||
static void CheckEncodeDecode(id value, NSData* expectedEncoding) {
|
||||
FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
|
||||
NSData* encoded = [codec encode:value];
|
||||
@ -252,3 +339,14 @@ TEST(FlutterStandardCodec, HandlesErrorEnvelopes) {
|
||||
id decoded = [codec decodeEnvelope:encoded];
|
||||
ASSERT_TRUE([decoded isEqual:error]);
|
||||
}
|
||||
|
||||
TEST(FlutterStandardCodec, HandlesSubclasses) {
|
||||
ExtendedReaderWriter* extendedReaderWriter = [[[ExtendedReaderWriter alloc] init] autorelease];
|
||||
FlutterStandardMessageCodec* codec =
|
||||
[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter];
|
||||
Pair* pair = [[[Pair alloc] initWithLeft:@1 right:@2] autorelease];
|
||||
NSData* encoded = [codec encode:pair];
|
||||
Pair* decoded = [codec decode:encoded];
|
||||
ASSERT_TRUE([pair.left isEqual:decoded.left]);
|
||||
ASSERT_TRUE([pair.right isEqual:decoded.right]);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user