mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Flesh out basic file I/O examples
This commit is contained in:
parent
224475a87d
commit
079311d080
5 changed files with 2765 additions and 40 deletions
|
@ -1,5 +1,5 @@
|
|||
interface File
|
||||
exposes [ReadErr, WriteErr, writeUtf8, writeBytes, readUtf8, readBytes]
|
||||
exposes [ReadErr, WriteErr, write, writeUtf8, writeBytes, readUtf8, readBytes]
|
||||
imports [Effect, Task.{ Task }, InternalTask, InternalFile, Path.{ Path }, InternalPath]
|
||||
|
||||
ReadErr : InternalFile.ReadErr
|
||||
|
@ -7,7 +7,7 @@ ReadErr : InternalFile.ReadErr
|
|||
WriteErr : InternalFile.WriteErr
|
||||
|
||||
## For example, suppose you have a [JSON](https://en.wikipedia.org/wiki/JSON)
|
||||
## [EncodingFormat] named `Json.toCompactUtf8`. Then you can use that format
|
||||
## `EncodingFormat` named `Json.toCompactUtf8`. Then you can use that format
|
||||
## to write some encodable data to a file as JSON, like so:
|
||||
##
|
||||
## File.write
|
||||
|
@ -24,12 +24,12 @@ WriteErr : InternalFile.WriteErr
|
|||
## This opens the file first and closes it after writing to it.
|
||||
##
|
||||
## To write unformatted bytes to a file, you can use [File.writeBytes] instead.
|
||||
# write : Path, val, fmt -> Task {} (WriteErr *) [Write [File]*]*
|
||||
# | val has Encode.Encoding, fmt has Encode.EncoderFormatting
|
||||
# write = \path, val, fmt ->
|
||||
# Encode.toBytes val fmt
|
||||
# # TODO handle encoding errors here, once they exist
|
||||
# |> writeBytes
|
||||
write : Path, val, fmt -> Task {} [FileWriteErr Path WriteErr]* [Write [File]*]*
|
||||
| val has Encode.Encoding, fmt has Encode.EncoderFormatting
|
||||
write = \path, val, fmt ->
|
||||
bytes = Encode.toBytes val fmt
|
||||
# TODO handle encoding errors here, once they exist
|
||||
writeBytes path bytes
|
||||
|
||||
## Write bytes to a file.
|
||||
##
|
||||
|
@ -39,12 +39,12 @@ WriteErr : InternalFile.WriteErr
|
|||
## This opens the file first and closes it after writing to it.
|
||||
##
|
||||
## To format data before writing it to a file, you can use [File.write] instead.
|
||||
writeBytes : Path, List U8 -> Task {} [FileWriteErr WriteErr]* [Write [File]*]*
|
||||
writeBytes : Path, List U8 -> Task {} [FileWriteErr Path WriteErr]* [Write [File]*]*
|
||||
writeBytes = \path, bytes ->
|
||||
InternalPath.toBytes path
|
||||
|> Effect.fileWriteBytes bytes
|
||||
|> InternalTask.fromEffect
|
||||
|> Task.mapFail FileWriteErr
|
||||
|> Task.mapFail \err -> FileWriteErr path err
|
||||
|
||||
## Write a [Str] to a file, encoded as [UTF-8](https://en.wikipedia.org/wiki/UTF-8).
|
||||
##
|
||||
|
@ -54,12 +54,12 @@ writeBytes = \path, bytes ->
|
|||
## This opens the file first and closes it after writing to it.
|
||||
##
|
||||
## To write unformatted bytes to a file, you can use [File.writeBytes] instead.
|
||||
writeUtf8 : Path, Str -> Task {} [FileWriteErr WriteErr]* [Write [File]*]*
|
||||
writeUtf8 : Path, Str -> Task {} [FileWriteErr Path WriteErr]* [Write [File]*]*
|
||||
writeUtf8 = \path, str ->
|
||||
InternalPath.toBytes path
|
||||
|> Effect.fileWriteUtf8 str
|
||||
|> InternalTask.fromEffect
|
||||
|> Task.mapFail FileWriteErr
|
||||
|> Task.mapFail \err -> FileWriteErr path err
|
||||
|
||||
## Read all the bytes in a file.
|
||||
##
|
||||
|
@ -68,13 +68,13 @@ writeUtf8 = \path, str ->
|
|||
##
|
||||
## This opens the file first and closes it after reading its contents.
|
||||
##
|
||||
## To read and decode data from a file, you can use [File.read] instead.
|
||||
readBytes : Path -> Task (List U8) [FileReadErr ReadErr]* [Read [File]*]*
|
||||
## To read and decode data from a file, you can use `File.read` instead.
|
||||
readBytes : Path -> Task (List U8) [FileReadErr Path ReadErr]* [Read [File]*]*
|
||||
readBytes = \path ->
|
||||
InternalPath.toBytes path
|
||||
|> Effect.fileReadBytes
|
||||
|> InternalTask.fromEffect
|
||||
|> Task.mapFail FileReadErr
|
||||
|> Task.mapFail \err -> FileReadErr path err
|
||||
|
||||
## Read a [Str] from a file containing [UTF-8](https://en.wikipedia.org/wiki/UTF-8)-encoded text.
|
||||
##
|
||||
|
@ -89,32 +89,33 @@ readUtf8 :
|
|||
Path
|
||||
-> Task
|
||||
Str
|
||||
[FileReadErr ReadErr, FileReadUtf8Err _]*
|
||||
[FileReadErr Path ReadErr, FileReadUtf8Err Path _]*
|
||||
[Read [File]*]*
|
||||
readUtf8 = \path ->
|
||||
effect = Effect.map (Effect.fileReadBytes (InternalPath.toBytes path)) \result ->
|
||||
when result is
|
||||
Ok bytes ->
|
||||
Str.fromUtf8 bytes
|
||||
|> Result.mapErr FileReadUtf8Err
|
||||
|> Result.mapErr \err -> FileReadUtf8Err path err
|
||||
|
||||
Err readErr -> Err (FileReadErr readErr)
|
||||
Err readErr -> Err (FileReadErr path readErr)
|
||||
|
||||
InternalTask.fromEffect effect
|
||||
|
||||
# read :
|
||||
# Path
|
||||
# Path,
|
||||
# fmt
|
||||
# -> Task
|
||||
# Str
|
||||
# [FileReadErr ReadErr, FileReadDecodeErr DecodeErr]*
|
||||
# [FileReadErr Path ReadErr, FileReadDecodeErr Path [Leftover (List U8)]Decode.DecodeError ]*
|
||||
# [Read [File]*]*
|
||||
# | val has Decode.Decoding, fmt has Decode.DecoderFormatting
|
||||
# read = \path ->
|
||||
# effect = Effect.after (Effect.fileReadBytes path) \result ->
|
||||
# read = \path, fmt ->
|
||||
# effect = Effect.map (Effect.fileReadBytes (InternalPath.toBytes path)) \result ->
|
||||
# when result is
|
||||
# Ok bytes ->
|
||||
# when Decode.fromBytes bytes fmt is
|
||||
# Ok val -> InternalTask.succeed val
|
||||
# Ok val -> Ok val
|
||||
# Err decodingErr -> Err (FileReadDecodeErr decodingErr)
|
||||
|
||||
# Err readErr -> Err (FileReadErr readErr)
|
||||
|
|
|
@ -2,6 +2,71 @@ interface InternalFile
|
|||
exposes [ReadErr, WriteErr]
|
||||
imports []
|
||||
|
||||
ReadErr : [NotFound, Other]
|
||||
ReadErr : [
|
||||
NotFound,
|
||||
Interrupted,
|
||||
InvalidFilename,
|
||||
PermissionDenied,
|
||||
TooManySymlinks, # aka FilesystemLoop
|
||||
TooManyHardlinks,
|
||||
TimedOut,
|
||||
StaleNetworkFileHandle,
|
||||
OutOfMemory,
|
||||
Unsupported,
|
||||
Unrecognized I32 Str,
|
||||
]
|
||||
|
||||
WriteErr : [PermissionDenied, Other]
|
||||
WriteErr : [
|
||||
NotFound,
|
||||
Interrupted,
|
||||
InvalidFilename,
|
||||
PermissionDenied,
|
||||
TooManySymlinks, # aka FilesystemLoop
|
||||
TooManyHardlinks,
|
||||
TimedOut,
|
||||
StaleNetworkFileHandle,
|
||||
ReadOnlyFilesystem,
|
||||
AlreadyExists, # can this happen here?
|
||||
WasADirectory,
|
||||
WriteZero, # TODO come up with a better name for this, or roll it into another error tag
|
||||
StorageFull,
|
||||
FilesystemQuotaExceeded, # can this be combined with StorageFull?
|
||||
FileTooLarge,
|
||||
ResourceBusy,
|
||||
ExecutableFileBusy,
|
||||
OutOfMemory,
|
||||
Unsupported,
|
||||
Unrecognized I32 Str,
|
||||
]
|
||||
|
||||
# DirReadErr : [
|
||||
# NotFound,
|
||||
# Interrupted,
|
||||
# InvalidFilename,
|
||||
# PermissionDenied,
|
||||
# TooManySymlinks, # aka FilesystemLoop
|
||||
# TooManyHardlinks,
|
||||
# TimedOut,
|
||||
# StaleNetworkFileHandle,
|
||||
# NotADirectory,
|
||||
# OutOfMemory,
|
||||
# Unsupported,
|
||||
# Unrecognized I32 Str,
|
||||
# ]
|
||||
|
||||
# RmDirError : [
|
||||
# NotFound,
|
||||
# Interrupted,
|
||||
# InvalidFilename,
|
||||
# PermissionDenied,
|
||||
# TooManySymlinks, # aka FilesystemLoop
|
||||
# TooManyHardlinks,
|
||||
# TimedOut,
|
||||
# StaleNetworkFileHandle,
|
||||
# NotADirectory,
|
||||
# ReadOnlyFilesystem,
|
||||
# DirectoryNotEmpty,
|
||||
# OutOfMemory,
|
||||
# Unsupported,
|
||||
# Unrecognized I32 Str,
|
||||
# ]
|
2643
examples/interactive/cli-platform/src/file_glue.rs
Normal file
2643
examples/interactive/cli-platform/src/file_glue.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
mod file_glue;
|
||||
mod glue;
|
||||
|
||||
use core::alloc::Layout;
|
||||
|
@ -14,6 +15,9 @@ use std::os::raw::c_char;
|
|||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use file_glue::ReadErr;
|
||||
use file_glue::WriteErr;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__mainForHost_1_exposed_generic"]
|
||||
fn roc_main(output: *mut u8);
|
||||
|
@ -136,24 +140,35 @@ pub extern "C" fn roc_fx_stderrLine(line: &RocStr) {
|
|||
eprintln!("{}", string);
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
// pub extern "C" fn roc_fx_fileWriteUtf8(
|
||||
// roc_path: &RocList<u8>,
|
||||
// roc_string: &RocStr,
|
||||
// // ) -> RocResult<(), WriteErr> {
|
||||
// ) -> (u8, u8) {
|
||||
// let _ = write_slice(roc_path, roc_string.as_str().as_bytes());
|
||||
|
||||
// (255, 255)
|
||||
// }
|
||||
|
||||
type Fail = Foo;
|
||||
|
||||
#[repr(C)]
|
||||
pub enum ReadErr {
|
||||
NotFound,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum WriteErr {
|
||||
Other,
|
||||
PermissionDenied,
|
||||
pub struct Foo {
|
||||
data: u8,
|
||||
tag: u8,
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
// pub extern "C" fn roc_fx_fileWriteUtf8(roc_path: &RocList<u8>, roc_string: &RocStr) -> Fail {
|
||||
// write_slice2(roc_path, roc_string.as_str().as_bytes())
|
||||
// }
|
||||
#[no_mangle]
|
||||
pub extern "C" fn roc_fx_fileWriteUtf8(
|
||||
roc_path: &RocList<u8>,
|
||||
roc_string: &RocStr,
|
||||
roc_str: &RocStr,
|
||||
) -> RocResult<(), WriteErr> {
|
||||
write_slice(roc_path, roc_string.as_str().as_bytes())
|
||||
write_slice(roc_path, roc_str.as_str().as_bytes())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
@ -11,6 +11,7 @@ main =
|
|||
|
||||
Task.attempt task \result ->
|
||||
when result is
|
||||
Ok {} -> Stdout.line "Successfully wrote a string to out.txt"
|
||||
Err (FileWriteErr PermissionDenied) -> Stderr.line "Err: PermissionDenied"
|
||||
Err (FileWriteErr Other) -> Stderr.line "Err: Other"
|
||||
Err (FileWriteErr _ PermissionDenied) -> Stderr.line "Err: PermissionDenied"
|
||||
Err (FileWriteErr _ Unsupported) -> Stderr.line "Err: Unsupported"
|
||||
Err (FileWriteErr _ (Unrecognized _ other)) -> Stderr.line "Err: \(other)"
|
||||
_ -> Stdout.line "Successfully wrote a string to out.txt"
|
Loading…
Add table
Add a link
Reference in a new issue