Skip to content

Commit

Permalink
The Prerelease 1 is coming! Main changes are:
Browse files Browse the repository at this point in the history
- JVM has finally got its actual implementations
- JVM implementation of FileContainer now uses its private fileInputStream to read the file in stream manner
- readUntil JVM implementation (currently its only implementation) is a now way more optimized than initial
- thanks to previous change readLine now cuts '\n' on the end by default
- writing is also included. Unlike C/C++ file APIs, when this library will come to Kotlin/Native, you will be able to change between appending and overwriting on the fly just by using two dedicated functions
  • Loading branch information
bpavuk committed Oct 14, 2023
1 parent bdb8a2d commit ad6e17d
Show file tree
Hide file tree
Showing 21 changed files with 271 additions and 103 deletions.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ build/
!**/src/test/**/build/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea
*.iws
*.iml
*.ipr
Expand Down
8 changes: 0 additions & 8 deletions .idea/.gitignore

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/artifacts/filery_js_0_1.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/artifacts/filery_jvm_0_1.xml

This file was deleted.

16 changes: 0 additions & 16 deletions .idea/gradle.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/inspectionProfiles/Project_Default.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/misc.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

16 changes: 15 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
plugins {
kotlin("multiplatform") version "1.9.0"
id("maven-publish")
}

group = "com.bpavuk"
version = "0.1"
version = "Prerelease_1"

repositories {
mavenCentral()
Expand Down Expand Up @@ -65,3 +66,16 @@ kotlin {
// val nativeTest by getting
}
}

publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/bpavuk/filery")
credentials {
username = System.getenv("GITHUB_USERNAME")
password = System.getenv("GITHUB_TOKEN")
}
}
}
}
76 changes: 45 additions & 31 deletions src/commonMain/kotlin/com/bpavuk/filery/Filery.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.bpavuk.filery

import com.bpavuk.filery.expects.FileContainerImpl
import com.bpavuk.filery.types.Modes
import com.bpavuk.filery.types.Path
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.io.Buffer

@DslMarker
Expand All @@ -17,56 +18,75 @@ internal annotation class FileryDsl
* around
*/
@Suppress("MemberVisibilityCanBePrivate")
public class Filery(public val path: String) {
public class Filery(
public val path: String,
private val createOnAbsence: Boolean = false
) {
private val buffer = Buffer()
private val container = FileContainerImpl(Path(path), buffer)
private val fileContainer = FileContainerImpl(Path(path), buffer)

public fun path(): String = path

public suspend fun open(mod: Modes = Modes.ReadWrite): Filery {
if (!container.isOpen(mod)) container.open(mod)
if (createOnAbsence && !fileContainer.exists()) fileContainer.create()
if (!fileContainer.isOpen(mod)) fileContainer.open(mod)
return this
}

public suspend fun isOpen(): Boolean = container.isOpen()
public suspend fun isOpen(): Boolean = fileContainer.isOpen()

public suspend fun close() {
container.close()
fileContainer.close()
}

public suspend fun readBytes(amount: Int = -1): ByteArray {

TODO("""
must read the file
""".trimIndent())
fileContainer.readBytes(amount)
return fileContainer.readBuffer()
}

public suspend fun readUntil(condition: Byte.() -> Boolean): ByteArray {
// val byteArray: MutableList<Byte> = mutableListOf()
// do {
// val byte = readBytes(amount = 1)[0]
// byteArray.add(byte)
// } while (!byte.condition())
// return ByteArray(byteArray.size) { byteArray[it] }

TODO("""
must be implemented on the native side
""".trimIndent())
public suspend fun readUntil(includeLastByte: Boolean = true, condition: Byte.() -> Boolean): ByteArray {
fileContainer.readUntil(includeLastByte, condition)
return fileContainer.readBuffer()
}

public suspend fun readText(amount: Int = -1): String {
return readBytes(amount).decodeToString()
fileContainer.readBytes(amount)
return fileContainer.readBufferAsString()
}

public suspend fun readLine(cutLineEscape: Boolean = true): String = readUntil(!cutLineEscape) {
this == '\n'.code.toByte()
}.decodeToString()

public suspend fun write(bytes: ByteArray) {
fileContainer.writeBytes(bytes)
fileContainer.writeToFile()
}

public suspend fun write(bytes: List<Byte>) {
write(bytes.toByteArray())
}

public suspend fun append(bytes: ByteArray) {
fileContainer.writeBytes(bytes)
fileContainer.appendToFile()
}

public suspend fun readLine(): ByteArray = readUntil { this == '\n'.code.toByte() }
public suspend fun fileExists(): Boolean = fileContainer.exists()
}

/**
* The Filery library starting point. It automatically opens your file by path, does what you wish
* to do and closes it safely. Preferred way to work with files
*/
public suspend inline fun filery(path: String, noinline block: suspend (@FileryDsl Filery).() -> Unit) {
public suspend inline fun filery(
path: String,
createFileOnAbsence: Boolean = false,
noinline block: suspend (@FileryDsl Filery).() -> Unit
) {
coroutineScope {
launch(Dispatchers.IO) {
val filery = Filery(path).open()
val filery = Filery(path, createFileOnAbsence).open()
val potentialException = runCatching { filery.block() }.exceptionOrNull()
filery.close()
if (potentialException != null) {
Expand All @@ -75,9 +95,3 @@ public suspend inline fun filery(path: String, noinline block: suspend (@FileryD
}
}
}

private fun main() = runBlocking {
filery("fuckery.txt") {
println(readLine())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.bpavuk.filery.exceptions

public class FileAlreadyClosedException(fileName: String) : RuntimeException("File $fileName already closed")
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.bpavuk.filery.exceptions

public class FileDoesNotExistException(fileName: String) : RuntimeException("file $fileName does not exist")
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.bpavuk.filery.exceptions

public class FileNotOpenException(fileName: String) : RuntimeException("file $fileName is not open")
53 changes: 50 additions & 3 deletions src/commonMain/kotlin/com/bpavuk/filery/expects/FileContainer.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,78 @@
package com.bpavuk.filery.expects

import com.bpavuk.filery.Modes
import com.bpavuk.filery.Path
import com.bpavuk.filery.types.FileType
import com.bpavuk.filery.types.Modes
import com.bpavuk.filery.types.Path
import kotlinx.io.Buffer
import kotlinx.io.readByteArray
import kotlinx.io.readString

public interface FileContainer {
public var file: FileryFile?
public var type: FileType?
public val buffer: Buffer

public var mode: Modes?

public suspend fun isOpen(mode: Modes = Modes.ReadWrite): Boolean =
file != null && this.mode == mode

// TODO: implement modes
public suspend fun open(mode: Modes)

public suspend fun create()

public suspend fun exists(): Boolean

public suspend fun close() {
file = null
mode = null
}

/**
* reads bytes to [buffer]
*/
public suspend fun readBytes(amount: Int)

public suspend fun readUntil(condition: Byte.() -> Boolean)
/**
* reads bytes to [buffer] until condition gives true
*/
public suspend fun readUntil(includeLastByte: Boolean = true, condition: Byte.() -> Boolean)

/**
* writes bytes to [buffer]
*/
public suspend fun writeBytes(bytes: ByteArray)

/**
* checks if current file is directory
*/
public suspend fun isDirectory(): Boolean

/**
* checks if current file is regular file (needed to avoid symlinks and other shenanigans)
*/
public suspend fun isRegularFile(): Boolean

/**
* reads the whole buffer and returns its contents
*/
public suspend fun readBuffer(): ByteArray = buffer.readByteArray()

/**
* same as [readBuffer] but returns content as string
*/
public suspend fun readBufferAsString(): String = buffer.readString()

/**
* writes directly from [buffer] to file, overwriting it
*/
public suspend fun writeToFile()

/**
* appends bytes from [buffer] to file instead of overwriting it
*/
public suspend fun appendToFile()
}

internal expect class FileContainerImpl(
Expand Down
7 changes: 7 additions & 0 deletions src/commonMain/kotlin/com/bpavuk/filery/types/FileType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.bpavuk.filery.types

public enum class FileType {
FILE,
DIRECTORY,
// more to come
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.bpavuk.filery
package com.bpavuk.filery.types

public enum class Modes(public val modName: String) {
Read("r"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.bpavuk.filery
package com.bpavuk.filery.types

public data class Path(public val path: String)
26 changes: 26 additions & 0 deletions src/commonTest/kotlin/ReadTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.bpavuk.filery.filery
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertTrue

class ReadTest {
@Test
fun testRead() = runTest {
filery("/home/bpavuk/fuckery.txt") {
assertTrue {
readLine(cutLineEscape = false) == "fuckery\n"
}
}
filery("/home/bpavuk/fuckery.txt") {
assertTrue {
readBytes(3).decodeToString() == "fuc"
}
assertTrue { readLine() == "kery" }
}
filery("/home/bpavuk/fuckery.txt") {
assertTrue {
readBytes().decodeToString() == "fuckery\n"
}
}
}
}
Loading

0 comments on commit ad6e17d

Please sign in to comment.