Home | History | Annotate | Download | only in async
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.async;
     18 
     19 import com.google.common.util.concurrent.AsyncFunction;
     20 import com.google.common.util.concurrent.ForwardingListenableFuture;
     21 import com.google.common.util.concurrent.Futures;
     22 import com.google.common.util.concurrent.ListenableFuture;
     23 
     24 import java.util.List;
     25 
     26 import javax.annotation.Nullable;
     27 
     28 /**
     29  * TODO Replace with Guava's com.google.common.util.concurrent.Futures once we
     30  * can build with v. 15+
     31  */
     32 public class Futures2 {
     33     /**
     34      * 2 parameter async function for joined async results.
     35      */
     36     public interface AsyncFunction2<T1, T2, TResult> {
     37         ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception;
     38     }
     39 
     40     /**
     41      * 3 parameter async function for joined async results.
     42      */
     43     public interface AsyncFunction3<T1, T2, T3, TResult> {
     44         ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception;
     45     }
     46 
     47     /**
     48      * 2 parameter function for joining multiple results into a single value.
     49      */
     50     public interface Function2<T1, T2, TResult> {
     51         TResult apply(T1 value1, T2 value2);
     52     }
     53 
     54     /**
     55      * 3 parameter function for joining multiple results into a single value.
     56      */
     57     public interface Function3<T1, T2, T3, TResult> {
     58         TResult apply(T1 value1, T2 value2, T3 value3);
     59     }
     60 
     61     private Futures2() {
     62     }
     63 
     64     /**
     65      * Creates a new ListenableFuture whose result is set from the supplied
     66      * future when it completes. Cancelling the supplied future will also cancel
     67      * the returned future, but cancelling the returned future will have no
     68      * effect on the supplied future.
     69      */
     70     public static <T> ListenableFuture<T> nonCancellationPropagating(
     71             final ListenableFuture<T> future) {
     72         return new ForwardingListenableFuture.SimpleForwardingListenableFuture<T>(future) {
     73             @Override
     74             public boolean cancel(boolean mayInterruptIfNecessary) {
     75                 return false;
     76             }
     77         };
     78     }
     79 
     80     /**
     81      * Create a new joined future from two existing futures and a joining function
     82      * that combines the resulting outputs of the previous functions into a single
     83      * result. The resulting future will fail if any of the dependent futures also
     84      * fail.
     85      */
     86     public static <T1, T2, TResult> ListenableFuture<TResult> joinAll(
     87           final ListenableFuture<T1> f1,
     88           final ListenableFuture<T2> f2,
     89           final AsyncFunction2<T1, T2, TResult> fn) {
     90         ListenableFuture<?>[] futures = new ListenableFuture<?>[2];
     91 
     92         futures[0] = f1;
     93         futures[1] = f2;
     94 
     95         // Futures.allAsList is used instead of Futures.successfulAsList because
     96         // allAsList will propagate the failures instead of null values to the
     97         // parameters of the supplied function.
     98         ListenableFuture<List<Object>> result = Futures.allAsList(futures);
     99         return Futures.transform(result, new AsyncFunction<List<Object>, TResult>() {
    100             @Override
    101             public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception {
    102                 T1 value1 = (T1) list.get(0);
    103                 T2 value2 = (T2) list.get(1);
    104 
    105                 return fn.apply(value1, value2);
    106             }
    107         });
    108     }
    109 
    110     /**
    111      * Create a new joined future from two existing futures and an async function
    112      * that combines the resulting outputs of the previous functions into a single
    113      * result. The resulting future will fail if any of the dependent futures also
    114      * fail.
    115      */
    116     public static <T1, T2, TResult> ListenableFuture<TResult> joinAll(
    117           final ListenableFuture<T1> f1,
    118           final ListenableFuture<T2> f2,
    119           final Function2<T1, T2, TResult> fn) {
    120         return joinAll(f1, f2, new ImmediateAsyncFunction2<>(fn));
    121     }
    122 
    123     /**
    124      * Create a new joined future from three existing futures and a joining function
    125      * that combines the resulting outputs of the previous functions into a single
    126      * result. The resulting future will fail if any of the dependent futures also
    127      * fail.
    128      */
    129     public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll(
    130           final ListenableFuture<T1> f1,
    131           final ListenableFuture<T2> f2,
    132           final ListenableFuture<T3> f3,
    133           final AsyncFunction3<T1, T2, T3, TResult> fn) {
    134         ListenableFuture<?>[] futures = new ListenableFuture<?>[3];
    135 
    136         futures[0] = f1;
    137         futures[1] = f2;
    138         futures[2] = f3;
    139 
    140         // Futures.allAsList is used instead of Futures.successfulAsList because
    141         // allAsList will propagate the failures instead of null values to the
    142         // parameters of the supplied function.
    143         ListenableFuture<List<Object>> result = Futures.allAsList(futures);
    144         return Futures.transform(result, new AsyncFunction<List<Object>, TResult>() {
    145             @Override
    146             public ListenableFuture<TResult> apply(@Nullable List<Object> list) throws Exception {
    147                 T1 value1 = (T1) list.get(0);
    148                 T2 value2 = (T2) list.get(1);
    149                 T3 value3 = (T3) list.get(2);
    150 
    151                 return fn.apply(value1, value2, value3);
    152             }
    153         });
    154     }
    155 
    156     /**
    157      * Create a new joined future from three existing futures and an async function
    158      * that combines the resulting outputs of the previous functions into a single
    159      * result. The resulting future will fail if any of the dependent futures also
    160      * fail.
    161      */
    162     public static <T1, T2, T3, TResult> ListenableFuture<TResult> joinAll(
    163           final ListenableFuture<T1> f1,
    164           final ListenableFuture<T2> f2,
    165           final ListenableFuture<T3> f3,
    166           final Function3<T1, T2, T3, TResult> fn) {
    167         return joinAll(f1, f2, f3, new ImmediateAsyncFunction3<>(fn));
    168     }
    169 
    170     /**
    171      * Wrapper class for turning a Function2 into an AsyncFunction2 by returning
    172      * an immediate future when the function is applied.
    173      */
    174     private static final class ImmediateAsyncFunction2<T1, T2, TResult> implements
    175           AsyncFunction2<T1, T2, TResult> {
    176         private final Function2<T1, T2, TResult> mFn;
    177 
    178         public ImmediateAsyncFunction2(Function2<T1, T2, TResult> fn) {
    179             mFn = fn;
    180         }
    181 
    182         @Override
    183         public ListenableFuture<TResult> apply(T1 value1, T2 value2) throws Exception {
    184             return Futures.immediateFuture(mFn.apply(value1, value2));
    185         }
    186     }
    187 
    188     /**
    189      * Wrapper class for turning a Function3 into an AsyncFunction3 by returning
    190      * an immediate future when the function is applied.
    191      */
    192     private static final class ImmediateAsyncFunction3<T1, T2, T3, TResult> implements
    193           AsyncFunction3<T1, T2, T3, TResult> {
    194         private final Function3<T1, T2, T3, TResult> mFn;
    195 
    196         public ImmediateAsyncFunction3(Function3<T1, T2, T3, TResult> fn) {
    197             mFn = fn;
    198         }
    199 
    200         @Override
    201         public ListenableFuture<TResult> apply(T1 value1, T2 value2, T3 value3) throws Exception {
    202             return Futures.immediateFuture(mFn.apply(value1, value2, value3));
    203         }
    204     }
    205 }
    206