// Copyright 2018 The Bazel Authors. All rights reserved. // // 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 com.google.devtools.build.lib.skyframe.serialization; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.ByteString; import javax.annotation.Nullable; /** * A container class that holds an {@link #object} of type {@link T} and a possibly null {@link * ListenableFuture}. If the {@link ListenableFuture} returned by {@link #getFutureToBlockWritesOn} * is non-null, then, if {@link #object} is the serialized representation of some Bazel object, then * it should not be written anywhere until the {@link ListenableFuture} in {@link * #getFutureToBlockWritesOn} completes successfully. * * @param Some serialized representation of an object, for instance a {@code byte[]} or a {@link * ByteString}. */ public abstract class SerializationResult { private final T object; private SerializationResult(T object) { this.object = object; } /** * Returns a new {@link SerializationResult} with the same future (if any) and {@code newObj} * replacing the current {@link #getObject}. */ public abstract SerializationResult with(S newObj); /** * Returns a {@link ListenableFuture} that, if not null, must complete successfully before {@link * #getObject} can be written remotely. */ @Nullable public abstract ListenableFuture getFutureToBlockWritesOn(); /** Returns the stored object that should not be written remotely before the future completes. */ public T getObject() { return object; } static SerializationResult create( T object, @Nullable ListenableFuture futureToBlockWritesOn) { return futureToBlockWritesOn != null ? new ObjectWithFuture<>(object, futureToBlockWritesOn) : createWithoutFuture(object); } /** Creates an {@link SerializationResult} with a null future (no waiting necessary. */ public static SerializationResult createWithoutFuture(T object) { return new ObjectWithoutFuture<>(object); } private static class ObjectWithoutFuture extends SerializationResult { ObjectWithoutFuture(T obj) { super(obj); } @Override public SerializationResult with(S newObj) { return new ObjectWithoutFuture<>(newObj); } @Override public ListenableFuture getFutureToBlockWritesOn() { return null; } } private static class ObjectWithFuture extends SerializationResult { private final ListenableFuture futureToBlockWritesOn; ObjectWithFuture(T obj, @Nullable ListenableFuture futureToBlockWritesOn) { super(obj); this.futureToBlockWritesOn = Preconditions.checkNotNull(futureToBlockWritesOn, obj); } @Override public SerializationResult with(S newObj) { return new ObjectWithFuture<>(newObj, futureToBlockWritesOn); } @Override public ListenableFuture getFutureToBlockWritesOn() { return futureToBlockWritesOn; } } }