| // 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(); |
| } |