├── .gitignore ├── .travis.yml ├── Changes.md ├── LICENSE ├── Makefile ├── README.md ├── lib ├── async │ ├── future.ml │ ├── future.mli │ └── std.ml ├── lwt │ ├── future.ml │ ├── future.mli │ └── std.ml └── unix │ ├── future.ml │ ├── future.mli │ ├── s.ml │ └── std.ml ├── myocamlbuild.ml └── opam ├── descr ├── findlib └── opam /.gitignore: -------------------------------------------------------------------------------- 1 | /_build/ 2 | /future.install 3 | /.merlin 4 | /.ocamlinit 5 | *~ 6 | /tmp 7 | /*.byte 8 | /*.native 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: required 3 | install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-opam.sh 4 | script: bash -ex .travis-opam.sh 5 | env: 6 | - OCAML_VERSION=4.02 PINS=solvuu-build 7 | - OCAML_VERSION=4.03 PINS=solvuu-build 8 | - OCAML_VERSION=4.04 PINS=solvuu-build 9 | os: 10 | - linux 11 | - osx 12 | -------------------------------------------------------------------------------- /Changes.md: -------------------------------------------------------------------------------- 1 | # Future release notes 2 | 3 | ## future 0.2.0 2016-09-28 4 | * Add more operations. 5 | * Use solvuu-build for build system. 6 | * Remove all uses of camlp4. 7 | 8 | ## future 0.1.0 2016-02-15 9 | * Initial release. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Solvuu LLC 2 | 3 | Permission to use, copy, modify, and/or distribute this software for 4 | any purpose with or without fee is hereby granted, provided that the 5 | above copyright notice and this permission notice appear in all 6 | copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(shell opam config var solvuu-build:lib)/solvuu.mk 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Future - Abstraction over Stdlib, Lwt, and Async. 2 | [![Build Status](https://travis-ci.org/solvuu/future.svg?branch=master)](https://travis-ci.org/solvuu/future) 3 | 4 | OCaml has two concurrency libraries in wide use: Lwt and Async. When 5 | writing your own library, the question is which of the two your API 6 | should be developed against. For example, if you provide a 7 | non-blocking function, should it return a `Lwt.t` or Async's 8 | `Deferred.t`? Ideally, you could provide both because that allows 9 | users of both Lwt and Async to use your new library. 10 | 11 | In addition, sometimes you want to provide a blocking implementation 12 | based on OCaml's Stdlib. Blocking APIs are easier for beginners to 13 | understand and sometimes provide faster code (if your program doesn't 14 | have much concurrency, the overhead of Lwt and Async is wasted time). 15 | 16 | This library provides a signature `Future.S` that abstracts over 17 | Stdlib, Lwt, and Async, and 3 implementations of it: `Future_std`, 18 | `Future_lwt`, and `Future_async`. The goal is to have Async.Std 19 | immediately satisfy this interface, i.e. to make `Future_async = 20 | Async.Std`. Thus, by functorizing your code over this interface, you 21 | can assume you are programming with Async (albeit with many fewer 22 | functions), and get Lwt and Stdlib versions of your code for free. 23 | 24 | We do not succeed in making `Future.S` an exact subset of `module type 25 | of Async.Std`. Sometimes a Lwt or Stdlib implementation of some Async 26 | construct is not possible or difficult. Such deviations are kept to a 27 | minimum and documented. Usually, if a feature cannot be supported 28 | uniformly for Stdlib, Lwt, and Async, then it is not included 29 | here. There is no goal to be comprehensive. Async is a large library 30 | and we are not attempting to provide compatible Stdlib and Lwt 31 | versions for all of it. 32 | -------------------------------------------------------------------------------- /lib/async/future.ml: -------------------------------------------------------------------------------- 1 | open Core.Std 2 | open Async.Std 3 | 4 | type how = Monad_sequence.how 5 | 6 | module Deferred = Deferred 7 | 8 | let return = return 9 | let (>>=) = (>>=) 10 | let (>>|) = (>>|) 11 | let (>>=?) = (>>=?) 12 | let (>>|?) = (>>|?) 13 | let fail = raise 14 | let raise = `Use_fail_instead 15 | let try_with f = try_with f 16 | 17 | module In_thread = struct 18 | include In_thread 19 | let run f = run f 20 | end 21 | 22 | 23 | module Pipe = struct 24 | include Pipe 25 | 26 | let read r = read r 27 | 28 | let junk r = 29 | read r >>= function 30 | | `Ok _ | `Eof -> Deferred.unit 31 | 32 | (* Author: Stephen Weeks. See here: 33 | https://groups.google.com/forum/#!topic/ocaml-core/6vskwLlFnS0 *) 34 | let rec peek_deferred r = 35 | match peek r with 36 | | Some x -> return (`Ok x) 37 | | None -> 38 | values_available r 39 | >>= function 40 | | `Eof -> return `Eof 41 | | `Ok -> peek_deferred r 42 | 43 | let map = map 44 | let fold r ~init ~f = fold r ~init ~f 45 | let iter r ~f = iter r ~f 46 | end 47 | 48 | module Reader = struct 49 | include Reader 50 | let open_file ?buf_len file = open_file ?buf_len file 51 | let with_file ?buf_len file ~f = with_file ?buf_len file ~f 52 | end 53 | 54 | module Writer = struct 55 | include Writer 56 | let with_file ?perm ?append file ~f = with_file ?perm ?append file ~f 57 | let write t x = write t x; Deferred.unit 58 | let write_char t x = write_char t x; Deferred.unit 59 | let write_line t x = write_line t x; Deferred.unit 60 | end 61 | 62 | module Sys = Sys 63 | 64 | module Unix = struct 65 | type file_perm = Unix.file_perm 66 | let getcwd = Unix.getcwd 67 | let rename = Unix.rename 68 | let getpid = Unix.getpid 69 | 70 | module Stats = struct 71 | type t = Core.Std.Unix.stats = { 72 | st_dev : int; 73 | st_ino : int; 74 | st_kind : Core.Std.Unix.file_kind; 75 | st_perm : file_perm; 76 | st_nlink : int; 77 | st_uid : int; 78 | st_gid : int; 79 | st_rdev : int; 80 | st_size : int64; 81 | st_atime : float; 82 | st_mtime : float; 83 | st_ctime : float; 84 | } 85 | end 86 | 87 | let stat x = In_thread.run (fun () -> Core.Std.Unix.stat x) 88 | let lstat x = In_thread.run (fun () -> Core.Std.Unix.lstat x) 89 | 90 | end 91 | -------------------------------------------------------------------------------- /lib/async/future.mli: -------------------------------------------------------------------------------- 1 | open Core.Std 2 | open Async.Std 3 | 4 | include Future_unix.Std.FUTURE 5 | with type 'a Deferred.t = 'a Deferred.t 6 | and type 'a Pipe.Reader.t = 'a Pipe.Reader.t 7 | and type Reader.t = Reader.t 8 | and type Writer.t = Writer.t 9 | -------------------------------------------------------------------------------- /lib/async/std.ml: -------------------------------------------------------------------------------- 1 | module type FUTURE = Future_unix.Std.FUTURE 2 | module Future = Future 3 | -------------------------------------------------------------------------------- /lib/lwt/future.ml: -------------------------------------------------------------------------------- 1 | open Core.Std 2 | open Lwt 3 | 4 | type how = [ `Parallel | `Sequential | `Max_concurrent_jobs of int ] 5 | 6 | module Deferred = struct 7 | type 'a t = 'a Lwt.t 8 | 9 | include Monad.Make(struct 10 | type 'a t = 'a Lwt.t 11 | let return = Lwt.return 12 | let bind = Lwt.bind 13 | let map = `Custom (fun m ~f -> Lwt.map f m) 14 | end) 15 | 16 | let unit = Lwt.return_unit 17 | 18 | module Result = struct 19 | type ('a, 'b) t = ('a, 'b) Result.t Lwt.t 20 | 21 | include Monad.Make2(struct 22 | type ('a, 'b) t = ('a, 'b) Result.t Lwt.t 23 | 24 | let return x = Lwt.return (Ok x) 25 | 26 | let bind m f = Lwt.bind m (function 27 | | Ok x -> f x 28 | | Error _ as x -> Lwt.return x 29 | ) 30 | 31 | let map = `Custom (fun m ~f -> Lwt.map (function 32 | | Ok x -> Ok (f x) 33 | | Error _ as x -> x 34 | ) m) 35 | end) 36 | end 37 | 38 | module List = struct 39 | 40 | let fold l ~init ~f = Lwt_list.fold_left_s f init l 41 | 42 | let iter ?(how = `Sequential) l ~f = 43 | match how with 44 | | `Sequential -> Lwt_list.iter_s f l 45 | | `Max_concurrent_jobs _ 46 | | `Parallel -> Lwt_list.iter_p f l 47 | 48 | let map ?(how = `Sequential) l ~f = 49 | match how with 50 | | `Sequential -> Lwt_list.map_s f l 51 | | `Max_concurrent_jobs _ 52 | | `Parallel -> Lwt_list.map_p f l 53 | 54 | let filter ?(how = `Sequential) l ~f = 55 | match how with 56 | | `Sequential -> Lwt_list.filter_s f l 57 | | `Max_concurrent_jobs _ 58 | | `Parallel -> Lwt_list.filter_p f l 59 | 60 | end 61 | 62 | module Or_error = struct 63 | module List = struct 64 | 65 | let map ?(how = `Sequential) l ~f = 66 | let map = match how with 67 | | `Sequential -> Lwt_list.map_s 68 | | `Max_concurrent_jobs _ 69 | | `Parallel -> Lwt_list.map_p 70 | in 71 | let module M = struct 72 | exception E of Error.t 73 | let helper () = map (fun x -> 74 | f x >>| function 75 | | Ok x -> x 76 | | Error e -> raise (E e) 77 | ) l 78 | end in 79 | try (M.helper() >>| fun x -> Ok x) 80 | with M.E e -> return (Error e) 81 | 82 | let iter ?(how = `Sequential) l ~f = 83 | let iter = match how with 84 | | `Sequential -> Lwt_list.iter_s 85 | | `Max_concurrent_jobs _ 86 | | `Parallel -> Lwt_list.iter_p 87 | in 88 | let module M = struct 89 | exception E of Error.t 90 | let helper () = iter (fun x -> 91 | f x >>| function 92 | | Ok () -> () 93 | | Error e -> raise (E e) 94 | ) l 95 | end in 96 | try (M.helper() >>| fun () -> Ok ()) 97 | with M.E e -> return (Error e) 98 | 99 | end 100 | end 101 | 102 | end 103 | 104 | let return = Deferred.return 105 | let (>>=) = Deferred.(>>=) 106 | let (>>|) = Deferred.(>>|) 107 | let (>>=?) = Deferred.Result.(>>=) 108 | let (>>|?) = Deferred.Result.(>>|) 109 | let fail = Lwt.fail 110 | let raise = `Use_fail_instead 111 | 112 | let try_with f = 113 | Lwt.catch 114 | (fun () -> f () >>| fun x -> Ok x) 115 | (fun exn -> return (Error exn)) 116 | 117 | 118 | module In_thread = struct 119 | let run f = Lwt_preemptive.detach f () 120 | end 121 | 122 | module Pipe = struct 123 | module Reader = struct 124 | type 'a t = 'a Lwt_stream.t 125 | end 126 | 127 | let read r = 128 | Lwt_stream.get r >>| function 129 | | Some x -> `Ok x 130 | | None -> `Eof 131 | 132 | let junk = Lwt_stream.junk 133 | 134 | let peek_deferred r = 135 | Lwt_stream.peek r >>| function 136 | | Some x -> `Ok x 137 | | None -> `Eof 138 | 139 | let map r ~f = Lwt_stream.map f r 140 | 141 | let fold r ~init ~f = 142 | Lwt_stream.fold_s (fun a accum -> f accum a) r init 143 | 144 | let iter r ~f = Lwt_stream.iter_s f r 145 | 146 | end 147 | 148 | module Reader = struct 149 | module Read_result = struct 150 | type 'a t = [ `Eof | `Ok of 'a ] 151 | end 152 | 153 | type t = Lwt_io.input_channel 154 | 155 | let open_file ?buf_len file = 156 | let buffer = Option.map buf_len ~f:Lwt_bytes.create in 157 | Lwt_io.open_file ?buffer ~mode:Lwt_io.input file 158 | 159 | let close = Lwt_io.close 160 | 161 | let with_file ?buf_len file ~f = 162 | let buffer = Option.map buf_len ~f:Lwt_bytes.create in 163 | Lwt_io.with_file ?buffer ~mode:Lwt_io.input file f 164 | 165 | let read_line ic = 166 | Lwt_io.read_line_opt ic >>| function 167 | | Some x -> `Ok x 168 | | None -> `Eof 169 | 170 | let read_all ic read_one = 171 | Lwt_stream.from (fun () -> match%lwt read_one ic with 172 | | `Ok x -> Lwt.return (Some x) 173 | | `Eof -> 174 | Lwt_io.close ic >>= fun () -> 175 | Lwt.return None 176 | ) 177 | 178 | let lines ic = read_all ic read_line 179 | 180 | let contents ic = 181 | Lwt_io.read ic >>= fun ans -> 182 | Lwt_io.close ic >>= fun () -> 183 | return ans 184 | 185 | let file_contents file = with_file file ~f:Lwt_io.read 186 | 187 | let file_lines file = 188 | Lwt_io.lines_of_file file 189 | |> Lwt_stream.to_list 190 | 191 | end 192 | 193 | module Writer = struct 194 | type t = Lwt_io.output_channel 195 | 196 | let with_file ?perm ?(append=false) file ~f = 197 | let flags = match append with 198 | | true -> Unix.([O_WRONLY; O_CREAT; O_APPEND]) 199 | | false -> Unix.([O_WRONLY; O_CREAT; O_TRUNC]) 200 | in 201 | Lwt_io.with_file ~flags ?perm ~mode:Lwt_io.output file f 202 | 203 | let write = Lwt_io.write 204 | let write_char = Lwt_io.write_char 205 | let write_line = Lwt_io.write_line 206 | end 207 | 208 | module Sys = struct 209 | include Sys 210 | let file_exists x = Lwt_preemptive.detach file_exists x 211 | 212 | let is_file ?follow_symlinks x = 213 | Lwt_preemptive.detach (is_file ?follow_symlinks) x 214 | 215 | let is_directory ?follow_symlinks x = 216 | Lwt_preemptive.detach (is_directory ?follow_symlinks) x 217 | 218 | end 219 | 220 | module Unix = struct 221 | 222 | type file_perm = Unix.file_perm 223 | 224 | (* Lwt doesn't provide a non-blocking version of getcwd because 225 | presumably it is doesn't block. However, Async does because it 226 | claims it could block. See 227 | https://sympa.inria.fr/sympa/arc/ocsigen/2013-09/msg00003.html. 228 | 229 | If we agreed it is non-blocking, then could implement as: 230 | 231 | let getcwd () = return (Unix.getcwd()) 232 | 233 | However, I think Async is right, so I wrap it in Lwt's 234 | detach. *) 235 | let getcwd () = Lwt_preemptive.detach Unix.getcwd () 236 | 237 | let rename ~src ~dst = Lwt_unix.rename src dst 238 | 239 | let getpid = Unix.getpid 240 | 241 | module Stats = struct 242 | type t = Unix.stats = { 243 | st_dev : int; 244 | st_ino : int; 245 | st_kind : Unix.file_kind; 246 | st_perm : file_perm; 247 | st_nlink : int; 248 | st_uid : int; 249 | st_gid : int; 250 | st_rdev : int; 251 | st_size : int64; 252 | st_atime : float; 253 | st_mtime : float; 254 | st_ctime : float; 255 | } 256 | end 257 | 258 | (** We don't call Lwt_unix's [stat] and [lstat] because they don't 259 | support large file sizes. *) 260 | let stat x = Lwt_preemptive.detach Unix.stat x 261 | let lstat x = Lwt_preemptive.detach Unix.lstat x 262 | 263 | end 264 | -------------------------------------------------------------------------------- /lib/lwt/future.mli: -------------------------------------------------------------------------------- 1 | open Core.Std 2 | open Lwt 3 | 4 | include Future_unix.Std.FUTURE 5 | with type 'a Deferred.t = 'a Lwt.t 6 | and type 'a Pipe.Reader.t = 'a Lwt_stream.t 7 | and type Reader.t = Lwt_io.input_channel 8 | and type Writer.t = Lwt_io.output_channel 9 | -------------------------------------------------------------------------------- /lib/lwt/std.ml: -------------------------------------------------------------------------------- 1 | module type FUTURE = Future_unix.Std.FUTURE 2 | module Future = Future 3 | -------------------------------------------------------------------------------- /lib/unix/future.ml: -------------------------------------------------------------------------------- 1 | open Core.Std 2 | open CFStream 3 | 4 | type how = [ `Parallel | `Sequential | `Max_concurrent_jobs of int ] 5 | 6 | module Deferred = struct 7 | type 'a t = 'a 8 | 9 | include Monad.Make(struct 10 | type 'a t = 'a 11 | let return x = x 12 | let bind m f = f m 13 | let map = `Custom (fun m ~f -> f m) 14 | end) 15 | 16 | let unit = () 17 | 18 | module Result = struct 19 | type ('a, 'b) t = ('a, 'b) Result.t 20 | 21 | include Monad.Make2(struct 22 | type ('a, 'b) t = ('a, 'b) Result.t 23 | let return = Result.return 24 | let bind = Result.bind 25 | let map = `Custom Result.map 26 | end) 27 | end 28 | 29 | module List = struct 30 | let fold = List.fold 31 | let iter ?how:_ l ~f = List.iter l ~f 32 | let map ?how:_ l ~f = List.map l ~f 33 | let filter ?how:_ l ~f = List.filter l ~f 34 | end 35 | 36 | module Or_error = struct 37 | module List = struct 38 | 39 | let map ?(how = `Sequential) l ~f = 40 | let () = ignore how in 41 | let module M = struct 42 | exception E of Error.t 43 | let helper () = List.map l ~f:(fun x -> match f x with 44 | | Ok x -> x 45 | | Error e -> raise (E e) 46 | ) 47 | end in 48 | try Ok (M.helper()) 49 | with M.E e -> Error e 50 | 51 | let iter ?(how = `Sequential) l ~f = 52 | let () = ignore how in 53 | let module M = struct 54 | exception E of Error.t 55 | let helper () = List.iter l ~f:(fun x -> match f x with 56 | | Ok () -> () 57 | | Error e -> raise (E e) 58 | ) 59 | end in 60 | try Ok (M.helper()) 61 | with M.E e -> Error e 62 | 63 | end 64 | end 65 | 66 | end 67 | 68 | let return = Deferred.return 69 | let (>>=) = Deferred.bind 70 | let (>>|) = Deferred.(>>|) 71 | let (>>=?) = Deferred.Result.(>>=) 72 | let (>>|?) = Deferred.Result.(>>|) 73 | let fail = raise 74 | let raise = `Use_fail_instead 75 | 76 | let try_with f = 77 | try Ok (f ()) 78 | with exn -> Error exn 79 | 80 | 81 | module In_thread = struct 82 | let run f = f () 83 | end 84 | 85 | module Pipe = struct 86 | module Reader = struct 87 | type 'a t = 'a Stream.t 88 | end 89 | 90 | let read r = match Stream.next r with 91 | | Some x -> `Ok x 92 | | None -> `Eof 93 | 94 | let junk = Stream.junk 95 | 96 | let peek_deferred r = match Stream.peek r with 97 | | Some x -> `Ok x 98 | | None -> `Eof 99 | 100 | let map = Stream.map 101 | let fold = Stream.fold 102 | let iter = Stream.iter 103 | 104 | end 105 | 106 | module Reader = struct 107 | module Read_result = struct 108 | type 'a t = [ `Eof | `Ok of 'a ] 109 | end 110 | 111 | type t = in_channel 112 | 113 | let open_file ?buf_len:_ file = 114 | In_channel.create file 115 | 116 | let close = In_channel.close 117 | 118 | let with_file ?buf_len file ~f = 119 | match buf_len with 120 | | None | Some _ -> In_channel.with_file file ~f 121 | 122 | let read_line ic = 123 | match In_channel.input_line ~fix_win_eol:true ic with 124 | | Some x -> `Ok x 125 | | None -> `Eof 126 | 127 | let read_all ic read_one = 128 | Stream.from (fun _ -> match read_one ic with 129 | | `Ok x -> Some x 130 | | `Eof -> In_channel.close ic; None 131 | ) 132 | 133 | let lines ic = read_all ic read_line 134 | let contents = In_channel.input_all 135 | let file_contents = In_channel.read_all 136 | let file_lines = In_channel.read_lines 137 | 138 | end 139 | 140 | module Writer = struct 141 | type t = out_channel 142 | 143 | let with_file ?perm ?append file ~f = 144 | Out_channel.with_file ?perm ?append file ~f 145 | 146 | let write = Out_channel.output_string 147 | let write_char = Out_channel.output_char 148 | let write_line t s = Out_channel.output_string t s; Out_channel.newline t 149 | end 150 | 151 | module Sys = struct 152 | include Sys 153 | let file_exists x = file_exists x 154 | let is_file ?follow_symlinks x = is_file ?follow_symlinks x 155 | let is_directory ?follow_symlinks x = is_directory ?follow_symlinks x 156 | end 157 | 158 | module Unix = struct 159 | include Unix 160 | 161 | module Stats = struct 162 | type t = Unix.stats = { 163 | st_dev : int; 164 | st_ino : int; 165 | st_kind : Unix.file_kind; 166 | st_perm : file_perm; 167 | st_nlink : int; 168 | st_uid : int; 169 | st_gid : int; 170 | st_rdev : int; 171 | st_size : int64; 172 | st_atime : float; 173 | st_mtime : float; 174 | st_ctime : float; 175 | } 176 | end 177 | 178 | let stat = stat 179 | let lstat = lstat 180 | 181 | end 182 | -------------------------------------------------------------------------------- /lib/unix/future.mli: -------------------------------------------------------------------------------- 1 | include S.S 2 | with type 'a Deferred.t = 'a 3 | and type 'a Pipe.Reader.t = 'a Stream.t 4 | and type Reader.t = in_channel 5 | and type Writer.t = out_channel 6 | -------------------------------------------------------------------------------- /lib/unix/s.ml: -------------------------------------------------------------------------------- 1 | (** Signature defining a small subset of Async's API. Async, Lwt, and 2 | Stdlib (blocking) implementations of this interface are provided. 3 | *) 4 | open Core.Std 5 | 6 | module type S = sig 7 | 8 | type how = [ `Parallel | `Sequential | `Max_concurrent_jobs of int ] 9 | (** [`Max_concurrent_jobs] supported only for Async 10 | implementation. The Lwt implementation treats this the same as 11 | [`Parallel]. Blocking implementation treats all as [`Sequential]. *) 12 | 13 | module Deferred : sig 14 | include Monad.S 15 | 16 | val unit : unit t 17 | 18 | module Result : Monad.S2 19 | with type ('a, 'b) t = ('a, 'b) Result.t t 20 | 21 | module List : sig 22 | val fold : 'a list -> init:'b -> f:('b -> 'a -> 'b t) -> 'b t 23 | val iter : ?how:how -> 'a list -> f:('a -> unit t) -> unit t 24 | val map : ?how:how -> 'a list -> f:('a -> 'b t) -> 'b list t 25 | val filter : ?how:how -> 'a list -> f:('a -> bool t) -> 'a list t 26 | end 27 | 28 | module Or_error : sig 29 | module List : sig 30 | 31 | val map 32 | : ?how:how 33 | -> 'a list 34 | -> f:('a -> 'b Or_error.t t) 35 | -> 'b list Or_error.t t 36 | 37 | val iter 38 | : ?how:how 39 | -> 'a list 40 | -> f:('a -> unit Or_error.t t) 41 | -> unit Or_error.t t 42 | 43 | end 44 | end 45 | 46 | end 47 | 48 | val return : 'a -> 'a Deferred.t 49 | val (>>=) : 'a Deferred.t -> ('a -> 'b Deferred.t) -> 'b Deferred.t 50 | val (>>|) : 'a Deferred.t -> ('a -> 'b) -> 'b Deferred.t 51 | 52 | val (>>=?) : 53 | ('a, 'b) Deferred.Result.t -> 54 | ('a -> ('c, 'b) Deferred.Result.t) -> 55 | ('c, 'b) Deferred.Result.t 56 | 57 | val (>>|?) : 58 | ('a, 'b) Deferred.Result.t -> 59 | ('a -> 'c) -> 60 | ('c, 'b) Deferred.Result.t 61 | 62 | (** Difference from Async: Use [fail] instead of [raise]. *) 63 | val fail : exn -> 'a Deferred.t 64 | val raise : [> `Use_fail_instead ] 65 | 66 | (** Async supports several extra parameters to this function, which 67 | we do not currently support. *) 68 | val try_with : (unit -> 'a Deferred.t) -> ('a, exn) Result.t Deferred.t 69 | 70 | 71 | module In_thread : sig 72 | val run : (unit -> 'a) -> 'a Deferred.t 73 | end 74 | 75 | module Pipe : sig 76 | module Reader : sig 77 | type 'a t 78 | end 79 | 80 | val read : 'a Reader.t -> [ `Eof | `Ok of 'a ] Deferred.t 81 | 82 | (** Discard one item from the pipe. Do nothing if pipe is already 83 | fully consumed. Difference from Async: This function is not 84 | defined. *) 85 | val junk : 'a Reader.t -> unit Deferred.t 86 | 87 | (** Like [read] but doesn't consume the item. Difference from 88 | Async: This function is not defined. We don't call this 89 | function [peek] because that is already another function in 90 | Async, which has different semantics. *) 91 | val peek_deferred : 'a Reader.t -> [ `Eof | `Ok of 'a ] Deferred.t 92 | 93 | val map : 'a Reader.t -> f:('a -> 'b) -> 'b Reader.t 94 | 95 | val fold : 96 | 'a Reader.t -> 97 | init:'accum -> 98 | f:('accum -> 'a -> 'accum Deferred.t) -> 99 | 'accum Deferred.t 100 | 101 | val iter : 102 | 'a Reader.t -> 103 | f:('a -> unit Deferred.t) -> 104 | unit Deferred.t 105 | 106 | end 107 | 108 | module Reader : sig 109 | module Read_result : sig 110 | type 'a t = [ `Eof | `Ok of 'a ] 111 | end 112 | 113 | type t 114 | 115 | (** Difference from Async: implementations should try to use 116 | [buf_len] but are not required to. *) 117 | val open_file : ?buf_len:int -> string -> t Deferred.t 118 | 119 | val close : t -> unit Deferred.t 120 | 121 | (** Difference from Async: implementations should try to use 122 | [buf_len] but are not required to. *) 123 | val with_file : 124 | ?buf_len:int -> 125 | string -> 126 | f:(t -> 'a Deferred.t) -> 127 | 'a Deferred.t 128 | 129 | val read_line : t -> string Read_result.t Deferred.t 130 | val read_all : t -> (t -> 'a Read_result.t Deferred.t) -> 'a Pipe.Reader.t 131 | val lines : t -> string Pipe.Reader.t 132 | val contents : t -> string Deferred.t 133 | val file_contents : string -> string Deferred.t 134 | val file_lines : string -> string list Deferred.t 135 | end 136 | 137 | module Writer : sig 138 | type t 139 | 140 | val with_file 141 | : ?perm:int 142 | -> ?append:bool 143 | -> string 144 | -> f:(t -> 'a Deferred.t) 145 | -> 'a Deferred.t 146 | 147 | (** Following functions returned a Deferred.t, while in Async they 148 | return unit. *) 149 | val write : t -> string -> unit Deferred.t 150 | val write_char : t -> char -> unit Deferred.t 151 | val write_line : t -> string -> unit Deferred.t 152 | 153 | end 154 | 155 | module Sys : sig 156 | val getenv : string -> string option 157 | val file_exists : string -> [ `No | `Unknown | `Yes ] Deferred.t 158 | 159 | val is_file 160 | : ?follow_symlinks:bool 161 | -> string 162 | -> [ `No | `Unknown | `Yes ] Deferred.t 163 | 164 | val is_directory 165 | : ?follow_symlinks:bool 166 | -> string 167 | -> [`Yes | `No | `Unknown ] Deferred.t 168 | 169 | end 170 | 171 | module Unix : sig 172 | type file_perm = Unix.file_perm 173 | val getcwd : unit -> string Deferred.t 174 | val rename : src:string -> dst:string -> unit Deferred.t 175 | val getpid : unit -> Pid.t 176 | 177 | module Stats : sig 178 | 179 | type t = Unix.stats = { 180 | st_dev : int; 181 | st_ino : int; 182 | st_kind : Unix.file_kind; 183 | st_perm : file_perm; 184 | st_nlink : int; 185 | st_uid : int; 186 | st_gid : int; 187 | st_rdev : int; 188 | st_size : int64; 189 | st_atime : float; 190 | st_mtime : float; 191 | st_ctime : float; 192 | } 193 | (** We really want this type to be equal to Async's 194 | Unix.Stats.t, which unfortunately differs from Core's. So we 195 | use Core's type because otherwise all implementations of 196 | this signature would have to depend on Async. *) 197 | 198 | end 199 | 200 | val stat : string -> Stats.t Deferred.t 201 | val lstat : string -> Stats.t Deferred.t 202 | 203 | end 204 | 205 | end 206 | -------------------------------------------------------------------------------- /lib/unix/std.ml: -------------------------------------------------------------------------------- 1 | module type FUTURE = S.S 2 | module Future = Future 3 | -------------------------------------------------------------------------------- /myocamlbuild.ml: -------------------------------------------------------------------------------- 1 | open Printf 2 | open Solvuu_build.Std 3 | open Solvuu_build.Util 4 | 5 | let project_name = "future" 6 | let version = "dev" 7 | 8 | let lib ?findlib_deps ?internal_deps ?ml_files lib_name : Project.item = 9 | Project.lib (sprintf "%s_%s" project_name lib_name) 10 | ~install:(`Findlib (sprintf "%s.%s" project_name lib_name)) 11 | ~dir:(sprintf "lib/%s" lib_name) 12 | ~style:(`Pack (sprintf "%s_%s" project_name lib_name)) 13 | ?findlib_deps 14 | ?internal_deps 15 | ?ml_files 16 | 17 | let unix = lib "unix" ~findlib_deps:["core"; "cfstream"] 18 | let async = lib "async" ~internal_deps:[unix] ~findlib_deps:["async"] 19 | let lwt = lib "lwt" ~internal_deps:[unix] 20 | ~findlib_deps:["lwt"; "lwt.preemptive"; "lwt.ppx"] 21 | 22 | let ocamlinit_postfix = [ 23 | "open Core.Std"; 24 | "open Async.Std"; 25 | "open Future_async.Std"; 26 | ] 27 | 28 | let optional_pkgs = ["async"; "lwt"] 29 | 30 | let items = 31 | [unix;async;lwt] |> 32 | List.filter ~f:(fun x -> Project.dep_opts_sat x optional_pkgs) 33 | 34 | ;; 35 | let () = Project.solvuu1 ~project_name ~version ~ocamlinit_postfix items 36 | -------------------------------------------------------------------------------- /opam/descr: -------------------------------------------------------------------------------- 1 | Abstraction over Stdlib, Lwt, Async, and more. 2 | -------------------------------------------------------------------------------- /opam/findlib: -------------------------------------------------------------------------------- 1 | future 2 | -------------------------------------------------------------------------------- /opam/opam: -------------------------------------------------------------------------------- 1 | opam-version: "1.2" 2 | maintainer: "Ashish Agarwal " 3 | authors: ["Solvuu"] 4 | license: "ISC" 5 | homepage: "https://github.com/solvuu/future" 6 | dev-repo: "https://github.com/solvuu/future.git" 7 | bug-reports: "https://github.com/solvuu/future/issues" 8 | tags: ["org:solvuu"] 9 | 10 | build: [ 11 | [make "byte"] 12 | [make "native"] 13 | [make "_build/META"] 14 | [make "future.install"] 15 | ] 16 | 17 | depends: [ 18 | "ocamlfind" {build} 19 | "ocamlbuild" {build} 20 | "solvuu-build" {build & >= "0.1.0"} 21 | "core" {>= "111.17.00"} 22 | "cfstream" 23 | ] 24 | 25 | depopts: [ 26 | "async" 27 | "lwt" 28 | ] 29 | 30 | conflicts: [ 31 | "async" {< "112.35.00"} 32 | "lwt" {< "2.5.0"} 33 | ] 34 | --------------------------------------------------------------------------------