Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support hooks for external Map and Array builders #14

Open
wevre opened this issue Mar 18, 2023 · 0 comments
Open

Support hooks for external Map and Array builders #14

wevre opened this issue Mar 18, 2023 · 0 comments

Comments

@wevre
Copy link

wevre commented Mar 18, 2023

@knopp Would you entertain a change that would let a user of the library have more control over how deserialized Arrays and Maps are built?

I'm working on an implementation of Cognitect's transit for Dart and in order to support MessagePack I need some guarantees about map entry orders. If such a hook was available in this API, I would be able to intercept the keys and values as they are being deserialized and be able to preserve their insertion order.

import 'dart:collection';

abstract class MapBuilder<G, M, K, V> {
  // Initialize a new (gestational) map
  G init();
  // Add key and val to the gestational map, return new gestational map, which
  // must be used for the next invocation.
  G add(G m, K key, V val);
  // Convert gestational map into final map and return it.
  M complete(G m);
}

// This is the default builder if the user does not provide a custom one.
class MapBuilderImpl implements MapBuilder<Map, Map, dynamic, dynamic> {
  @override
  init() => Map();

  @override
  add(m, key, val) {
    m[key] = val;
    return m;
  }

  @override
  complete(m) => m;
}

class Deserializer {
  final ExtDecoder? _extDecoder;
  final MapBuilder _mapBuilder;                            //<-- this is new
  final codec = Utf8Codec();
  final Uint8List _list;
  final ByteData _data;
  int _offset = 0;

  Deserializer(
    Uint8List list, {
    ExtDecoder? extDecoder,
    this.copyBinaryData = false,
    MapBuilder? mapBuilder                                 //<-- this is new
  })  : _list = list,
        _data = ByteData.view(list.buffer, list.offsetInBytes),
        _extDecoder = extDecoder,
        _mapBuilder = mapBuilder ?? MapBuilderImpl();      //<-- this is new

  // ... SKIPPING ...

  // Delegates to `mapBuilder` for actual map construction, always passing in
  // the result of the previous call as input to the next call.
  Map _readMap(int length) {
    var mr = _mapBuilder.init();
    while (length > 0) {
      mr = _mapBuilder.add(mr, decode(), decode());
      --length;
    }
    return _mapBuilder.complete(mr);
  }
}

In my case, I would register a MapBuilder that initialized a LinkHashMap in order to preserve insertion order.

If this is something you'd consider, I'll create a PR. If not, I'll just create a fork.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant