Index: samples/todomvc/dart/todomvc_presenter_model.dart |
diff --git a/samples/todomvc/dart/todomvc_presenter_model.dart b/samples/todomvc/dart/todomvc_presenter_model.dart |
deleted file mode 100644 |
index 7572b6bb0c4fbe3765d6789277001fade687d44b..0000000000000000000000000000000000000000 |
--- a/samples/todomvc/dart/todomvc_presenter_model.dart |
+++ /dev/null |
@@ -1,378 +0,0 @@ |
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE.md file. |
- |
-// Should become auto-generated. |
- |
-library todomvc_presenter_model; |
- |
-import 'todomvc_service.dart'; |
- |
-/* |
- The presentation model should be generated by a terse description. |
- For example, the presenter model for this sample might have been declared as: |
- |
- struct Immutable { |
- union { |
- Atom; |
- Cons; |
- } |
- } |
- |
- struct Atom { |
- union { |
- void nil; |
- int32 num; |
- bool truth; |
- String str; |
- } |
- } |
- |
- struct Cons { |
- Immutable fst; |
- Immutable snd; |
- } |
- |
- service TodoListPresenter { |
- void Create(String); |
- void Delete(Int32); |
- void Complete(Int32); |
- void Clear(); |
- } |
- |
- From the description we would generate dart classes and their path descriptors |
- for each struct together with the diff algorithm. For services we would create |
- command descriptors. All of these would come with serialization support for |
- wire transfer. |
- |
- Until then, all of the above is implemented below. |
- |
- */ |
- |
-// Tracing to ease debugging on dartino... |
-bool TRACE = false; |
-void trace(obj) { if (TRACE) print(" $obj"); } |
- |
-// Some constants. |
- |
-const TAG_CONS_FST = 0; |
-const TAG_CONS_SND = 1; |
-const TAG_CONS_DELETE_EVENT = 2; |
-const TAG_CONS_COMPLETE_EVENT = 3; |
-const TAG_CONS_UNCOMPLETE_EVENT = 4; |
- |
-// The event manager maintains a mapping from the active handler ids transferred |
-// as part of the presentation graph to the handler callbacks. |
-class EventManager { |
- Map<int, EventHandler> _handlers = new Map(); |
- |
- int _lfsr = 0xABBA; |
- |
- int get _next { |
- // 16 bits with taps 16, 14, 13, 11. |
- int lfsr = _lfsr; |
- int bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) & 1; |
- lfsr = (lfsr >> 1) | (bit << 15); |
- _lfsr = lfsr; |
- return lfsr; |
- } |
- |
- int register(EventHandler handler) { |
- if (handler == null) return 0; |
- if (handler.allocated) { |
- // After event manager reset we must re-register event handlers. |
- int id = handler.id; |
- EventHandler registered = _handlers[id]; |
- if (registered == null) { |
- _handlers[id] = handler; |
- } else if (registered != handler) { |
- print("ERROR: attempt to re-register event handler: $id"); |
- } |
- return id; |
- } |
- int id = _next; |
- // TODO(zerny): Do something clever once completing the lfsr sequence. |
- while (_handlers.containsKey(id)) id = _next; |
- trace("registered event-handler id: $id"); |
- _handlers[id] = handler; |
- handler.allocate(id); |
- return id; |
- } |
- |
- void unregister(EventHandler handler) { |
- if (handler == null) return; |
- // TODO(zerny): replace by assert. |
- int id = handler.id; |
- if (!handler.allocated) { |
- print("ERROR: attempt to unregister unallocated event handler: $id"); |
- return; |
- } |
- trace("unregistered event-handler id: $id"); |
- assert(_handlers[id] == handler); |
- handler.delete(); |
- _handlers.remove(id); |
- } |
- |
- void call(int id) { |
- assert(id > 0); |
- EventHandler handler = _handlers[id]; |
- if (handler == null) { |
- print("ERROR: attempt to call non-exisiting event handler: $id"); |
- return; |
- } |
- handler.call(); |
- } |
- |
- void clear() { |
- _handlers.clear(); |
- } |
-} |
- |
-// Immutable model for the presentation (reused as a mutable mirror on the |
-// "host" side). (just sexp to simulate a "rich structure" for now) |
- |
-abstract class Immutable { |
- void diff(Immutable other, Path path, MyPatchSet patches); |
- void serialize(NodeBuilder builder, EventManager events); |
- void unregisterEvents(EventManager events); |
-} |
- |
-class EventHandler extends Immutable { |
- final Function _handler; |
- int _id = 0; |
- |
- EventHandler(this._handler); |
- |
- int get id => _id; |
- bool get allocated => _id > 0; |
- bool get deleted => _id < 0; |
- |
- void call() { |
- assert(allocated); |
- _handler(); |
- } |
- |
- void allocate(int id) { |
- assert(!deleted); |
- _id = id; |
- } |
- |
- void delete() { |
- _id = -1; |
- } |
- |
- static void staticDiff(EventHandler self, |
- EventHandler other, |
- Path path, |
- MyPatchSet patches) { |
- if (identical(self, other)) return; |
- // TODO(zerny): Do we want to consider another definition of equality here? |
- // Currently only the same physically allocated event-handler object is |
- // considered "the same", but we could refine that to be if the _handler |
- // object is "the same" (which it typically won't be because of closure |
- // allocation). Also, if we do so, we need to make sure that the allocated |
- // event ids are updated to be the same too, otherwise we could end up with |
- // an unallocated event handler being referenced from the binding layer. |
- patches.add(path, self, other); |
- } |
- |
- void diff(Immutable other, Path path, MyPatchSet patches) { |
- EventHandler.staticDiff(this, other, path, patches); |
- } |
- |
- // TODO(zerny): Event handler fields should not be encoded in Node. |
- void serialize(NodeBuilder builder, EventManager events) { |
- builder.num = events.register(this); |
- } |
- |
- void unregisterEvents(EventManager events) { |
- events.unregister(this); |
- } |
-} |
- |
-abstract class Atom extends Immutable { |
- final value; |
- Atom(this.value) { |
- trace("Allocating Atom"); |
- } |
- String toString() => "value($value)"; |
- |
- void diff(Immutable other, Path path, MyPatchSet patches) { |
- trace("Atom::diff $this ~=~ $other"); |
- if (other is Atom && value == other.value) |
- return; |
- patches.add(path, this, other); |
- } |
- |
- void unregisterEvents(EventManager events) { } |
-} |
- |
-class Cons extends Immutable { |
- final Immutable fst, snd; |
- final EventHandler deleteEvent, completeEvent, uncompleteEvent; |
- |
- Cons(this.fst, this.snd, |
- [ this.deleteEvent, |
- this.completeEvent, |
- this.uncompleteEvent ]) { |
- trace("Allocating Cons"); |
- } |
- |
- String toString() => "($fst . $snd)"; |
- |
- void diff(Immutable other, Path path, MyPatchSet patches) { |
- if (identical(this, other)) return; |
- if (other is! Cons) { |
- patches.add(path, this, other); |
- return; |
- } |
- Cons otherCons = other; |
- fst.diff(otherCons.fst, new ConsFst(path), patches); |
- snd.diff(otherCons.snd, new ConsSnd(path), patches); |
- EventHandler.staticDiff( |
- deleteEvent, |
- otherCons.deleteEvent, |
- new ConsDeleteEvent(path), patches); |
- EventHandler.staticDiff( |
- completeEvent, |
- otherCons.completeEvent, |
- new ConsCompleteEvent(path), patches); |
- EventHandler.staticDiff( |
- uncompleteEvent, |
- otherCons.uncompleteEvent, |
- new ConsUncompleteEvent(path), patches); |
- } |
- |
- void serialize(NodeBuilder builder, EventManager events) { |
- trace("Cons::serialize: $this"); |
- ConsBuilder cons = builder.initCons(); |
- cons.deleteEvent = events.register(deleteEvent); |
- cons.completeEvent = events.register(completeEvent); |
- cons.uncompleteEvent = events.register(uncompleteEvent); |
- fst.serialize(cons.initFst(), events); |
- snd.serialize(cons.initSnd(), events); |
- } |
- |
- void unregisterEvents(EventManager events) { |
- events.unregister(deleteEvent); |
- events.unregister(completeEvent); |
- events.unregister(uncompleteEvent); |
- fst.unregisterEvents(events); |
- snd.unregisterEvents(events); |
- } |
-} |
- |
-class Nil extends Atom { |
- Nil() : super(null); |
- void serialize(NodeBuilder builder, EventManager events) { |
- trace("Nil::serialize"); |
- builder.setNil(); |
- } |
-} |
- |
-class Bool extends Atom { |
- Bool(bool value) : super(value); |
- void serialize(NodeBuilder builder, EventManager events) { |
- trace("Bool::serialize: $this"); |
- builder.truth = value; |
- } |
-} |
- |
-class Num extends Atom { |
- Num(num value) : super(value); |
- void serialize(NodeBuilder builder, EventManager events) { |
- trace("Num::serialize: $this"); |
- builder.num = value; |
- } |
-} |
- |
-class Str extends Atom { |
- Str(String value) : super(value); |
- void serialize(NodeBuilder builder, EventManager events) { |
- trace("Str::serialize: $this"); |
- builder.str = value; |
- } |
-} |
- |
- |
-// Path in the immutable model. (We probably won't need an actual representation |
-// of these. We could just construct the serialized form on the fly). |
- |
-// Note that (serialize) reverses the path description. Ie, we construct the |
-// path 'inside-out' and read it 'outside-in' on the host side. |
- |
-abstract class Path { |
- final Path parent; |
- Path(this.parent); |
- int get tag; |
- |
- static void serialize(Path inner, PatchBuilder builder) { |
- trace("Path::serialize: path($inner)"); |
- int length = 0; |
- for (Path current = inner; current != null; current = current.parent) { |
- ++length; |
- } |
- var out = builder.initPath(length); |
- for (Path current = inner; current != null; current = current.parent) { |
- out[--length] = current.tag; |
- } |
- } |
- |
- String toString() => "$parent;$tag"; |
-} |
- |
-class ConsFst extends Path { |
- ConsFst(Path parent) : super(parent); |
- int get tag => TAG_CONS_FST; |
-} |
- |
-class ConsSnd extends Path { |
- ConsSnd(Path parent) : super(parent); |
- int get tag => TAG_CONS_SND; |
-} |
- |
-class ConsDeleteEvent extends Path { |
- ConsDeleteEvent(Path parent) : super(parent); |
- int get tag => TAG_CONS_DELETE_EVENT; |
-} |
- |
-class ConsCompleteEvent extends Path { |
- ConsCompleteEvent(Path parent) : super(parent); |
- int get tag => TAG_CONS_COMPLETE_EVENT; |
-} |
- |
-class ConsUncompleteEvent extends Path { |
- ConsUncompleteEvent(Path parent) : super(parent); |
- int get tag => TAG_CONS_UNCOMPLETE_EVENT; |
-} |
- |
-// Patch description |
- |
-class MyPatchSet { |
- List<Patch> patches = new List<Patch>(); |
- add(Path path, Immutable content, Immutable oldContent) => |
- patches.add(new Patch(path, content, oldContent)); |
- |
- void serialize(PatchSetBuilder builder, EventManager events) { |
- var length = patches.length; |
- trace("MyPatchSet::serialize: length($length)"); |
- var out = builder.initPatches(patches.length); |
- for (int i = 0; i < length; ++i) { |
- patches[i].serialize(out[i], events); |
- } |
- } |
-} |
- |
-class Patch { |
- Path path; |
- Immutable content; |
- Immutable oldContent; |
- Patch(this.path, this.content, this.oldContent); |
- |
- void serialize(PatchBuilder builder, EventManager events) { |
- trace("Patch::serialize"); |
- oldContent.unregisterEvents(events); |
- Path.serialize(path, builder); |
- content.serialize(builder.initContent(), events); |
- } |
-} |