
io.datakernel.csp.queue.ChannelZeroBuffer Maven / Gradle / Ivy
Show all versions of datakernel-csp Show documentation
/*
* Copyright (C) 2015-2018 SoftIndex LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datakernel.csp.queue;
import io.datakernel.promise.Promise;
import io.datakernel.promise.SettablePromise;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static io.datakernel.common.Recyclable.tryRecycle;
/**
* Represents a buffer of zero capacity and stores only
* one value. There are {@code take} and {@code put}
* {@link SettablePromise}s which represent status of
* corresponding operations. Unless they are {@code null},
* they are waiting for the operation to be completed.
*
* @param type of data passed through the buffer
*/
public final class ChannelZeroBuffer implements ChannelQueue {
private Exception exception;
@Nullable
private T value;
@Nullable
private SettablePromise put;
@Nullable
private SettablePromise take;
/**
* Shows if this buffer is waiting for take
* or put operation to be completed.
*
* @return {@code true} if either {@code put}
* or {@code take} doesn't equal {@code null}
*/
public boolean isWaiting() {
return take != null || put != null;
}
public boolean isWaitingPut() {
return put != null;
}
public boolean isWaitingTake() {
return take != null;
}
/**
* Sets the provided {@code value} to current {@code value},
* then sets {@code put} as a new {@link SettablePromise}
* and returns it.
*
* If {@code take} isn't {@code null}, the {@code value}
* will be set to it.
*
* Current {@code put} must be {@code null}. If current
* {@code exception} is not {@code null}, provided
* {@code value} will be recycled and a promise of the
* exception will be returned.
*
* @param value a value passed to the buffer
* @return {@code put} if current {@code take} is {@code null},
* otherwise returns a successfully completed promise. If
* current {@code exception} is not {@code null}, a promise of
* the {@code exception} will be returned.
*/
@Override
public Promise put(@Nullable T value) {
assert put == null;
if (exception == null) {
if (take != null) {
SettablePromise take = this.take;
this.take = null;
take.set(value);
return Promise.complete();
}
this.value = value;
this.put = new SettablePromise<>();
return put;
} else {
tryRecycle(value);
return Promise.ofException(exception);
}
}
/**
* Returns a promise of current {@code value}, if
* the {@code put} is not {@code null}.
*
* Sets {@code put} and {@code value} as {@code null}
* after the operation.
*
* If the {@code put} is {@code null}, sets {@code take}
* as a new {@link SettablePromise} and returns it. If
* current {@code exception} is not {@code null}, returns
* a promise of the exception and does nothing else.
*
* @return a promise of the {@code value} or of {@code null}.
* If this {@code exception} is not {@code null}, returns a
* promise of exception.
*/
@Override
public Promise take() {
assert take == null;
if (exception == null) {
if (put != null) {
T value = this.value;
SettablePromise put = this.put;
this.value = null;
this.put = null;
put.set(null);
return Promise.of(value);
}
this.take = new SettablePromise<>();
return take;
} else {
return Promise.ofException(exception);
}
}
/**
* Closes the buffer if this {@code exception} is not
* {@code null}. Recycles all elements of the buffer and
* sets {@code elements}, {@code put} and {@code take} to
* {@code null}.
*
* @param e exception that is used to close buffer with
*/
@Override
public void close(@NotNull Throwable e) {
if (exception != null) return;
exception = e instanceof Exception ? (Exception) e : new RuntimeException(e);
if (put != null) {
put.setException(e);
put = null;
}
if (take != null) {
take.setException(e);
take = null;
}
tryRecycle(value);
value = null;
}
@Nullable
public Throwable getException() {
return exception;
}
}