forked from tpolecat/doobie
-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.scala
105 lines (88 loc) · 3.23 KB
/
io.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright (c) 2013-2020 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT
package doobie.util
import cats.effect.kernel.Sync
import cats.effect.kernel.syntax.monadCancel.*
import cats.syntax.applicative.*
import cats.syntax.flatMap.*
import cats.syntax.functor.*
import cats.syntax.monad.*
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
/**
* Module for a constructor of modules of IO operations for effectful monads.
*/
object io {
/**
* Constructor for a module of IO operations in some effectful monad. This is
* by no means complete; contributions welcome. The construtors here expose
* naked lifetime-managed objects and should be used with caution; they are
* mostly intended for library authors who wish to integrate vendor- specific
* behavior that relies on JDK IO.
*/
class IOActions[M[_]](implicit M: Sync[M]) {
private def delay[A](a: => A): M[A] = M.delay(a)
/**
* Print to `Console.out`
* @group Console Operations
*/
def putStr(s: String): M[Unit] =
delay(Console.out.print(s))
/**
* Print to `Console.out`
* @group Console Operations
*/
def putStrLn(s: String): M[Unit] =
delay(Console.out.println(s))
/**
* Copy a block from `is` to `os` using naked buffer `buf`, which will be
* clobbered.
* @group Stream Operations
*/
def copyBlock(buf: Array[Byte])(is: InputStream, os: OutputStream): M[Int] =
delay(is.read(buf)) flatMap { n => delay(os.write(buf, 0, n)).whenA(n >= 0).as(n) }
/**
* Copy the contents of `file` to a `os` in blocks of size `bufSize`.
* @group File Operations
*/
def copyFileToStream(bufSize: Int, file: File, os: OutputStream): M[Unit] =
withFileInputStream(file)(copyStream(new Array[Byte](bufSize))(_, os))
/**
* Copy the remainder of `is` to `file` in blocks of size `bufSize`.
* @group File Operations
*/
def copyStreamToFile(bufSize: Int, file: File, is: InputStream): M[Unit] =
withFileOutputStream(file)(copyStream(new Array[Byte](bufSize))(is, _))
/**
* Copy the remainder of `is` into `os` using naked buffer `buf`, which will
* be clobbered.
* @group Stream Operations
*/
def copyStream(buf: Array[Byte])(is: InputStream, os: OutputStream): M[Unit] =
copyBlock(buf)(is, os).iterateUntil(_ < 0).void
/**
* Perform an operation with a `FileInputStream`, which will be closed
* afterward.
* @group File Operations
*/
def withFileInputStream[A](file: File)(f: FileInputStream => M[A]): M[A] =
delay(new FileInputStream(file)).bracket(f)(i => delay(i.close()))
/**
* Perform an operation with a `FileOutputStream`, which will be closed
* afterward.
* @group File Operations
*/
def withFileOutputStream[A](file: File)(f: FileOutputStream => M[A]): M[A] =
delay(new FileOutputStream(file)).bracket(f)(i => delay(i.close()))
/**
* Flush `os`.
* @group Stream Operations
*/
def flush(os: OutputStream): M[Unit] =
delay(os.flush())
}
}