This commit is contained in:
SuperCraftAlex
2024-03-09 20:26:04 +01:00
parent 6f80ab30a3
commit b3150fd948
10 changed files with 196 additions and 13 deletions

View File

@@ -6,7 +6,8 @@ to drastically decrease the amount of single reads in the original source.
Example: Example:
```kt ```kt
File("text.txt") // File Path("text.txt") // Path
.getFile() // File
.openRead() // BatchSequence<Byte> .openRead() // BatchSequence<Byte>
.batched(64) // BatchSequence<Byte> .batched(64) // BatchSequence<Byte>
``` ```
@@ -21,6 +22,7 @@ Example:
val data = myData // Sequence<Byte> val data = myData // Sequence<Byte>
.asBatch() // BatchSequence<Byte> .asBatch() // BatchSequence<Byte>
File("text.txt") Path("text.txt") // Path
.getOrCreateFile() // File
.write(data) .write(data)
``` ```

View File

@@ -32,10 +32,10 @@ class Either<A, B> private constructor(
if (isA) af(a!!.v) else bf(b!!.v) if (isA) af(a!!.v) else bf(b!!.v)
fun <RA> mapA(transform: (A) -> RA): Either<RA, B> = fun <RA> mapA(transform: (A) -> RA): Either<RA, B> =
Either(a.map(transform), b) Either(a.mapNotNull(transform), b)
fun <RB> mapB(transform: (B) -> RB): Either<A, RB> = fun <RB> mapB(transform: (B) -> RB): Either<A, RB> =
Either(a, b.map(transform)) Either(a, b.mapNotNull(transform))
override fun toString(): String = override fun toString(): String =
if (isA) "Either<A>($a)" if (isA) "Either<A>($a)"

View File

@@ -1,5 +1,8 @@
package blitz package blitz
import blitz.func.*
import blitz.func.io.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
// pureCat(args) // pureCat(args)
// .impure() // .impure()

View File

@@ -0,0 +1,8 @@
package blitz
fun <R> modifyException(new: Throwable, block: () -> R): R =
try {
block()
} catch (e: Throwable) {
throw new
}

View File

@@ -0,0 +1,4 @@
package blitz.func
infix fun <A, B, C> Pair<A, B>.tri(c: C): Triple<A, B, C> =
Triple(first, second, c)

View File

@@ -14,3 +14,19 @@ fun <T> Sequence<Monad<T>>.rewrap(): Monad<Sequence<T>> =
val iter = this@rewrap.iterator() val iter = this@rewrap.iterator()
sequence { if (iter.hasNext()) yield(iter.next().impure()) } sequence { if (iter.hasNext()) yield(iter.next().impure()) }
} }
fun <A, B> Monad<Pair<A, B>>.rewrap(): Pair<Monad<A>, Monad<B>> {
val v = lazy { impure() }
return Monad { v.value.first } to Monad { v.value.second }
}
fun <A, B> Pair<Monad<A>, Monad<B>>.rewrap(): Monad<Pair<A, B>> =
Monad { first.impure() to second.impure() }
fun <A, B, C> Monad<Triple<A, B, C>>.rewrap(): Triple<Monad<A>, Monad<B>, Monad<C>> {
val v = lazy { impure() }
return Monad { v.value.first } to Monad { v.value.second } tri Monad { v.value.third }
}
fun <A, B, C> Triple<Monad<A>, Monad<B>, Monad<C>>.rewrap(): Monad<Triple<A, B, C>> =
Monad { first.impure() to second.impure() tri third.impure() }

View File

@@ -1,13 +1,32 @@
package blitz.func.io package blitz.func.io
import blitz.func.Monad import blitz.*
import blitz.func.bind import blitz.func.*
import blitz.io.readerSequence import blitz.io.*
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
fun Monad<String>.asPath() = fun Monad<String>.asPath(): Monad<Path> =
bind { Path(it) } bind { Path.of(it) }
fun Monad<Path>.read() = fun Monad<Path>.read(): Monad<ByteBatchSequence> =
bind { p -> { SystemFileSystem.source(p) }.readerSequence() } bind { it.getFile().read() }
fun Monad<Path>.write(seq: Monad<ByteBatchSequence>): Monad<Unit> =
bind { it.getFile().write(seq.impure()) }
fun Monad<Path>.append(seq: Monad<ByteBatchSequence>): Monad<Unit> =
bind { it.getFile().append(seq.impure()) }
fun Monad<ByteBatchSequence>.writeTo(path: Monad<Path>): Monad<Unit> =
path.write(this)
fun Monad<ByteBatchSequence>.appendTo(path: Monad<Path>): Monad<Unit> =
path.append(this)
fun Monad<Path>.exists(): Monad<Boolean> =
bind { it.exists() }
fun Monad<Path>.isDir(): Monad<Boolean> =
bind { it.isDir() }
fun Monad<Path>.isFile(): Monad<Boolean> =
bind { it.isFile() }

View File

@@ -0,0 +1,6 @@
package blitz.io
@JvmInline
value class Dir internal constructor(
val path: Path
)

View File

@@ -0,0 +1,34 @@
package blitz.io
import blitz.ByteBatchSequence
import kotlinx.io.Buffer
import kotlinx.io.files.SystemFileSystem
@JvmInline
value class File internal constructor(
val path: Path
)
fun File.read(): ByteBatchSequence =
path.toKotlinxPath().let {
{ SystemFileSystem.source(it) }
}.readerSequence()
private fun File.writeAppendFrom(seq: ByteBatchSequence, append: Boolean) {
val path = path.toKotlinxPath()
SystemFileSystem.sink(path, append).use { sink ->
val iter = seq.iterator()
while (iter.hasNext()) {
val batch = iter.nextBytes(8192)
val buff = Buffer()
buff.write(batch)
sink.write(buff, buff.size)
}
}
}
fun File.write(seq: ByteBatchSequence) =
writeAppendFrom(seq, false)
fun File.append(seq: ByteBatchSequence) =
writeAppendFrom(seq, true)

View File

@@ -0,0 +1,91 @@
package blitz.io
import blitz.modifyException
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.files.SystemPathSeparator
/**
* Every instance of this class represents an absolute path in a file system.
*/
@JvmInline
value class Path(
val parts: Array<String>
) {
val full: String
get() = parts.joinToString(separator.toString())
val name: String
get() = parts.last()
fun parent(): Path? =
if (parts.isEmpty()) null
else Path(parts.dropLast(1).toTypedArray())
// TODO: remove "." and ".." from the path
fun child(vararg paths: String): Path =
modifyException(Exception("children in Path.child() can not contain path separator!")) {
Path(parts + paths.onEach { assert(separator !in it) })
}
fun exists(): Boolean =
SystemFileSystem.exists(toKotlinxPath())
internal fun toKotlinxPath() =
kotlinx.io.files.Path("", *parts)
private fun kotlinxMeta() =
SystemFileSystem.metadataOrNull(toKotlinxPath())
fun isDir() =
kotlinxMeta()?.isDirectory ?: false
fun isFile() =
kotlinxMeta()?.isRegularFile ?: false
fun getDir(): Dir {
if (!exists()) throw Exception("Path does not exist!")
return Dir(this)
}
fun getOrCreateDir(): Dir {
if (!exists()) SystemFileSystem.createDirectories(toKotlinxPath())
return Dir(this)
}
fun getFile(): File {
if (!exists()) throw Exception("Path does not exist!")
return File(this)
}
fun getOrCreateFile(): File {
if (!exists()) SystemFileSystem.sink(toKotlinxPath()).flush()
return File(this)
}
fun deleteFileOrDir() {
if (!exists()) throw Exception("Path does not exist!")
SystemFileSystem.delete(toKotlinxPath())
}
fun tryDeleteFileOrDir() {
try {
if (exists())
SystemFileSystem.delete(toKotlinxPath())
} catch (_: Exception) {}
}
companion object {
val separator: Char = SystemPathSeparator
/**
* Creates a path from a relative or absolute path string.
*/
fun of(path: String): Path {
if (path.isEmpty()) return Path(emptyArray())
val kx = kotlinx.io.files.Path(path)
if (kx.isAbsolute)
return Path(path.substring(1).split(separator).toTypedArray())
return of(SystemFileSystem.resolve(kx).toString())
}
}
}