<commit_before>package tink.state.internal;

@:callable
private abstract Computation<T>((T->Void)->?Noise->T) {
  inline function new(f) this = f;

  @:from static function asyncWithLast<T>(f:Option<T>->Promise<T>):Computation<Promised<T>> {
    var link:CallbackLink = null,
        last = None,
        ret = Loading;
    return new Computation((update, ?_) -> {
      ret = Loading;
      link.cancel();
      link = f(last).handle(o -> update(ret = switch o {
        case Success(v): last = Some(v); Done(v);
        case Failure(e): Failed(e);
      }));
      return ret;
    });
  }


  @:from static function async<T>(f:Void->Promise<T>):Computation<Promised<T>>
    return asyncWithLast(_ -> f());

  @:from static inline function withLast<T>(f:Option<T>->T):Computation<T> {
    var last = None;
    return new Computation((_, ?_) -> {
      var ret = f(last);
      last = Some(ret);
      return ret;
    });
  }

  @:from static function sync<T>(f:Void->T) {
    return new Computation((_, ?_) -> f());
  }
}

private typedef Subscription = SubscriptionTo<Any>;

private class SubscriptionTo<T> {

  public final source:ObservableObject<T>;
  var last:T;
  var lastRev:Revision;
  var link:CallbackLink;
  final owner:Invalidatable;

  public var used = true;

  #if tink_state.test_subscriptions
    var connected:Bool = false;
  #end

  public function new<X>(source, cur, owner:AutoObservable<X>) {
    this.source = source;
    this.last = cur;
    this.lastRev = source.getRevision();
    this.owner = owner;

    if (owner.hot) connect();
  }

  public function isValid()
    return source.getRevision() == lastRev;

  public function hasChanged():Bool {
    var nextRev = source.getRevision();
    if (nextRev == lastRev) return false;
    lastRev = nextRev;
    var before = last;
    last = Observable.untracked(source.getValue);// not sure this has to be untracked
    return !source.getComparator().eq(last, before);
  }

  public function disconnect():Void {
    #if tink_state.test_subscriptions
      if (connected) {
        @:privateAccess AutoObservable.subscriptionCount--;
        connected = false;
      }
      else throw 'what?';
    #end
    link.cancel();
  }

  public function connect():Void {
    #if tink_state.test_subscriptions
      if (connected) throw 'what?';
      else {
        connected = true;
        @:privateAccess AutoObservable.subscriptionCount++;
      }
    #end
    this.link = source.onInvalidate(owner);
  }
}
<commit_msg>Inline all the things \o/<commit_after>package tink.state.internal;

@:callable
private abstract Computation<T>((T->Void)->?Noise->T) {
  inline function new(f) this = f;

  @:from static function asyncWithLast<T>(f:Option<T>->Promise<T>):Computation<Promised<T>> {
    var link:CallbackLink = null,
        last = None,
        ret = Loading;
    return new Computation((update, ?_) -> {
      ret = Loading;
      link.cancel();
      link = f(last).handle(o -> update(ret = switch o {
        case Success(v): last = Some(v); Done(v);
        case Failure(e): Failed(e);
      }));
      return ret;
    });
  }


  @:from static function async<T>(f:Void->Promise<T>):Computation<Promised<T>>
    return asyncWithLast(_ -> f());

  @:from static inline function withLast<T>(f:Option<T>->T):Computation<T> {
    var last = None;
    return new Computation((_, ?_) -> {
      var ret = f(last);
      last = Some(ret);
      return ret;
    });
  }

  @:from static function sync<T>(f:Void->T) {
    return new Computation((_, ?_) -> f());
  }
}

private typedef Subscription = SubscriptionTo<Any>;

private class SubscriptionTo<T> {

  public final source:ObservableObject<T>;
  var last:T;
  var lastRev:Revision;
  var link:CallbackLink;
  final owner:Invalidatable;

  public var used = true;

  #if tink_state.test_subscriptions
    var connected:Bool = false;
  #end

  public function new<X>(source, cur, owner:AutoObservable<X>) {
    this.source = source;
    this.last = cur;
    this.lastRev = source.getRevision();
    this.owner = owner;

    if (owner.hot) connect();
  }

  public inline function isValid()
    return source.getRevision() == lastRev;

  public inline function hasChanged():Bool {
    var nextRev = source.getRevision();
    if (nextRev == lastRev) return false;
    lastRev = nextRev;
    var before = last;
    last = Observable.untracked(source.getValue);// not sure this has to be untracked
    return !source.getComparator().eq(last, before);
  }

  public inline function disconnect():Void {
    #if tink_state.test_subscriptions
      if (connected) {
        @:privateAccess AutoObservable.subscriptionCount--;
        connected = false;
      }
      else throw 'what?';
    #end
    link.cancel();
  }

  public inline function connect():Void {
    #if tink_state.test_subscriptions
      if (connected) throw 'what?';
      else {
        connected = true;
        @:privateAccess AutoObservable.subscriptionCount++;
      }
    #end
    this.link = source.onInvalidate(owner);
  }
}

{'fraction_non_alphanumeric': 0.13881132828081372, 'fraction_numerical': 0.0, 'mean_word_length': 3.0541632983023446, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4030323', 'n_tokens_mistral': 1615, 'n_tokens_neox': 1585, 'n_words': 382}