blob: 0403ea473e1f1a69ed571e2922772bfd4e7887cf [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:meta/meta.dart';
/// The [EntityCodec] is a typed [Codec] which translates
/// entity data between the [Uint8List] wire format and a
/// dart object.
///
/// [EntityCodec]s have a specific semantic type and encoding
/// which allow them to operate with the entity system.
abstract class EntityCodec<T> extends Codec<T, Uint8List> {
/// The semantic type of the entity which this codec supports.
/// This type will be used when requesting entities from the
/// framework.
final String type;
/// The encoding that this [EntityCodec] knows how to encode/decode data
final String encoding;
/// The default constructor.
const EntityCodec({
@required this.type,
@required this.encoding,
}) : assert(type != null),
assert(encoding != null);
}
/// A [Codec] used for handling the the automatic translation to and from an
/// Entity's source data to the specified Dart type [T].
class SimpleEntityCodec<T> extends EntityCodec<T> {
final _EntityEncoder<T> _encoder;
final _EntityDecoder<T> _decoder;
/// Create a new [EntityCodec].
SimpleEntityCodec({
@required String type,
@required String encoding,
@required _EncodeEntity<T> encode,
@required _DecodeEntity<T> decode,
}) : assert(type != null),
assert(encoding != null),
assert(encode != null),
assert(decode != null),
_encoder = _EntityEncoder<T>(encode),
_decoder = _EntityDecoder<T>(decode),
super(type: type, encoding: encoding);
@override
_EntityEncoder<T> get encoder => _encoder;
@override
_EntityDecoder<T> get decoder => _decoder;
}
typedef _EncodeEntity<T> = Uint8List Function(T value);
class _EntityEncoder<T> extends Converter<T, Uint8List> {
final _EncodeEntity<T> encode;
const _EntityEncoder(this.encode);
@override
Uint8List convert(T source) {
return encode(source);
}
}
typedef _DecodeEntity<T> = T Function(Uint8List data);
class _EntityDecoder<T> extends Converter<Uint8List, T> {
final _DecodeEntity<T> decode;
const _EntityDecoder(this.decode);
@override
T convert(Uint8List data) => decode(data);
@override
Stream<T> bind(Stream<Uint8List> source) {
_EntityDecoderSink<T> map(EventSink<T> out) =>
new _EntityDecoderSink<T>(out, this);
return new Stream<T>.eventTransformed(source, map);
}
}
/// Entity data [String]s in, [T] out.
class _EntityDecoderSink<T> extends EventSink<Uint8List> {
/// The [EventSink] that values are decoded into. Errors generated by the
/// decoder are also added to [out].
final EventSink<T> out;
/// The decoder to used to convert the source ([Stream<String>]) events.
final _EntityDecoder<T> decoder;
/// Create an instance of [_EntityDecoderSink], usually via the
/// [Stream#eventTransformed] constructor.
_EntityDecoderSink(this.out, this.decoder);
@override
void add(Uint8List data) {
try {
T value = decoder.decode(data);
out.add(value);
} on Object catch (err, stackTrace) {
addError(err, stackTrace);
}
}
@override
void addError(Object e, [StackTrace s]) => out.addError(e, s);
@override
void close() => out.close();
}