class RateLimiterImpl<R> implements RateLimiter<R> {
  private final RateLimiterConfig<R> config;
  private final RateLimiterStats stats;

  public RateLimiterImpl(RateLimiterConfig<R> config) {
    this(config, new Stopwatch());
  }

  RateLimiterImpl(RateLimiterConfig<R> config, Stopwatch stopwatch) {
    this.config = config;
    stats = config.getMaxRate() != null ?
      new SmoothRateLimiterStats(config, stopwatch) :
      new BurstyRateLimiterStats(config, stopwatch);
  }

  @Override
  public RateLimiterConfig<R> getConfig() {
    return config;
  }

  @Override
  public void acquirePermits(int permits) throws InterruptedException {
    long waitNanos = reservePermits(permits).toNanos();
    if (waitNanos > 0)
      TimeUnit.NANOSECONDS.sleep(waitNanos);
  }

  @Override
  public Duration reservePermits(int permits) {
    Assert.isTrue(permits > 0, "permits must be > 0");
    return Duration.ofNanos(stats.acquirePermits(permits, null));
  }

  @Override
  public boolean tryAcquirePermits(int permits) {
    return reservePermits(permits, Duration.ZERO) == 0;
  }

  @Override
  public boolean tryAcquirePermits(int permits, Duration maxWaitTime) throws InterruptedException {<FILL_FUNCTION_BODY>}

  @Override
  public Duration tryReservePermits(int permits, Duration maxWaitTime) {
    return Duration.ofNanos(reservePermits(permits, maxWaitTime));
  }

  @Override
  public PolicyExecutor<R> toExecutor(int policyIndex) {
    return new RateLimiterExecutor<>(this, policyIndex);
  }

  long reservePermits(int permits, Duration maxWaitTime) {
    Assert.isTrue(permits > 0, "permits must be > 0");
    Assert.notNull(maxWaitTime, "maxWaitTime");
    return stats.acquirePermits(permits, Durations.ofSafeNanos(maxWaitTime));
  }
}

    long waitNanos = reservePermits(permits, maxWaitTime);
    if (waitNanos == -1)
      return false;
    if (waitNanos > 0)
      TimeUnit.NANOSECONDS.sleep(waitNanos);
    return true;
  
<no_super_class>