♻️ Extract file backend into utils subpackage

This commit is contained in:
Nanaloveyuki
2026-05-20 08:44:54 +08:00
parent 41d221af46
commit ac45ec2b03
5 changed files with 215 additions and 134 deletions
+20 -100
View File
@@ -1,117 +1,37 @@
fn string_to_c_bytes(str : String) -> Bytes { pub type FileHandle = @utils.FileHandle
let res : Array[Byte] = []
let len = str.length() pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
let mut i = 0 @utils.open_file_handle_internal(path, append)
while i < len {
let mut c = str.code_unit_at(i).to_int()
if 0xD800 <= c && c <= 0xDBFF {
c -= 0xD800
i = i + 1
let l = str.code_unit_at(i).to_int() - 0xDC00
c = (c << 10) + l + 0x10000
}
if c < 0x80 {
res.push(c.to_byte())
} else if c < 0x800 {
res.push((0xc0 + (c >> 6)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
} else if c < 0x10000 {
res.push((0xe0 + (c >> 12)).to_byte())
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
} else {
res.push((0xf0 + (c >> 18)).to_byte())
res.push((0x80 + ((c >> 12) & 0x3f)).to_byte())
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
}
i = i + 1
}
res.push((0).to_byte())
Bytes::from_array(res)
} }
#external pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
type NativeFileHandle @utils.write_file_handle_internal(handle, content)
#borrow(path, mode)
extern "C" fn file_open_ffi(path : Bytes, mode : Bytes) -> NativeFileHandle = "fopen"
extern "C" fn file_is_null_ffi(handle : NativeFileHandle) -> Bool = "moonbitlang_async_pointer_is_null"
#borrow(buffer)
extern "C" fn file_write_ffi(
buffer : Bytes,
size : Int,
count : Int,
handle : NativeFileHandle,
) -> Int = "fwrite"
extern "C" fn file_flush_ffi(handle : NativeFileHandle) -> Int = "fflush"
extern "C" fn file_close_ffi(handle : NativeFileHandle) -> Int = "fclose"
extern "C" fn file_seek_ffi(handle : NativeFileHandle, offset : Int, origin : Int) -> Int = "fseek"
extern "C" fn file_tell_ffi(handle : NativeFileHandle) -> Int = "ftell"
#borrow(from_path, to_path)
extern "C" fn file_rename_ffi(from_path : Bytes, to_path : Bytes) -> Int = "rename"
#borrow(path)
extern "C" fn file_remove_ffi(path : Bytes) -> Int = "remove"
pub struct FileHandle {
path : String
raw : NativeFileHandle
} }
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? { pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
let mode = if append { "ab" } else { "wb" } @utils.flush_file_handle_internal(handle)
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes(mode))
if file_is_null_ffi(raw) {
None
} else {
Some({ raw, path })
}
} }
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool { pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
let bytes = string_to_c_bytes(content) @utils.close_file_handle_internal(handle)
let written = file_write_ffi(bytes, 1, bytes.length() - 1, handle.raw)
written == bytes.length() - 1
} }
fn flush_file_handle_internal(handle : FileHandle) -> Bool { pub fn file_size_internal(handle : FileHandle) -> Int {
file_flush_ffi(handle.raw) == 0 @utils.file_size_internal(handle)
} }
fn close_file_handle_internal(handle : FileHandle) -> Bool { pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
file_close_ffi(handle.raw) == 0 @utils.rename_file_internal(from_path, to_path)
} }
fn file_size_internal(handle : FileHandle) -> Int { pub fn remove_file_internal(path : String) -> Bool {
ignore(file_seek_ffi(handle.raw, 0, 2)) @utils.remove_file_internal(path)
let size = file_tell_ffi(handle.raw)
if size < 0 {
0
} else {
size
}
} }
fn rename_file_internal(from_path : String, to_path : String) -> Bool { pub fn string_byte_length_internal(content : String) -> Int {
file_rename_ffi(string_to_c_bytes(from_path), string_to_c_bytes(to_path)) == 0 @utils.string_byte_length_internal(content)
} }
fn remove_file_internal(path : String) -> Bool { pub fn native_files_supported_internal() -> Bool {
file_remove_ffi(string_to_c_bytes(path)) == 0 @utils.native_files_supported_internal()
}
fn string_byte_length_internal(content : String) -> Int {
string_to_c_bytes(content).length() - 1
}
fn native_files_supported_internal() -> Bool {
true
} }
+20 -34
View File
@@ -1,51 +1,37 @@
pub struct FileHandle { pub type FileHandle = @utils.FileHandle
path : String
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
@utils.open_file_handle_internal(path, append)
} }
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? { pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
ignore(append) @utils.write_file_handle_internal(handle, content)
ignore(path)
let _unused : FileHandle = { path: "" }
ignore(_unused)
None
} }
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool { pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
ignore(handle) @utils.flush_file_handle_internal(handle)
ignore(content)
false
} }
fn flush_file_handle_internal(handle : FileHandle) -> Bool { pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
ignore(handle) @utils.close_file_handle_internal(handle)
false
} }
fn close_file_handle_internal(handle : FileHandle) -> Bool { pub fn file_size_internal(handle : FileHandle) -> Int {
ignore(handle) @utils.file_size_internal(handle)
false
} }
fn file_size_internal(handle : FileHandle) -> Int { pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
ignore(handle) @utils.rename_file_internal(from_path, to_path)
0
} }
fn rename_file_internal(from_path : String, to_path : String) -> Bool { pub fn remove_file_internal(path : String) -> Bool {
ignore(from_path) @utils.remove_file_internal(path)
ignore(to_path)
false
} }
fn remove_file_internal(path : String) -> Bool { pub fn string_byte_length_internal(content : String) -> Int {
ignore(path) @utils.string_byte_length_internal(content)
false
} }
fn string_byte_length_internal(content : String) -> Int { pub fn native_files_supported_internal() -> Bool {
content.length() @utils.native_files_supported_internal()
}
fn native_files_supported_internal() -> Bool {
false
} }
+117
View File
@@ -0,0 +1,117 @@
fn string_to_c_bytes(str : String) -> Bytes {
let res : Array[Byte] = []
let len = str.length()
let mut i = 0
while i < len {
let mut c = str.code_unit_at(i).to_int()
if 0xD800 <= c && c <= 0xDBFF {
c -= 0xD800
i = i + 1
let l = str.code_unit_at(i).to_int() - 0xDC00
c = (c << 10) + l + 0x10000
}
if c < 0x80 {
res.push(c.to_byte())
} else if c < 0x800 {
res.push((0xc0 + (c >> 6)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
} else if c < 0x10000 {
res.push((0xe0 + (c >> 12)).to_byte())
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
} else {
res.push((0xf0 + (c >> 18)).to_byte())
res.push((0x80 + ((c >> 12) & 0x3f)).to_byte())
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
res.push((0x80 + (c & 0x3f)).to_byte())
}
i = i + 1
}
res.push((0).to_byte())
Bytes::from_array(res)
}
#external
type NativeFileHandle
#borrow(path, mode)
extern "C" fn file_open_ffi(path : Bytes, mode : Bytes) -> NativeFileHandle = "fopen"
extern "C" fn file_is_null_ffi(handle : NativeFileHandle) -> Bool = "moonbitlang_async_pointer_is_null"
#borrow(buffer)
extern "C" fn file_write_ffi(
buffer : Bytes,
size : Int,
count : Int,
handle : NativeFileHandle,
) -> Int = "fwrite"
extern "C" fn file_flush_ffi(handle : NativeFileHandle) -> Int = "fflush"
extern "C" fn file_close_ffi(handle : NativeFileHandle) -> Int = "fclose"
extern "C" fn file_seek_ffi(handle : NativeFileHandle, offset : Int, origin : Int) -> Int = "fseek"
extern "C" fn file_tell_ffi(handle : NativeFileHandle) -> Int = "ftell"
#borrow(from_path, to_path)
extern "C" fn file_rename_ffi(from_path : Bytes, to_path : Bytes) -> Int = "rename"
#borrow(path)
extern "C" fn file_remove_ffi(path : Bytes) -> Int = "remove"
pub struct FileHandle {
path : String
raw : NativeFileHandle
}
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
let mode = if append { "ab" } else { "wb" }
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes(mode))
if file_is_null_ffi(raw) {
None
} else {
Some({ raw, path })
}
}
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
let bytes = string_to_c_bytes(content)
let written = file_write_ffi(bytes, 1, bytes.length() - 1, handle.raw)
written == bytes.length() - 1
}
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
file_flush_ffi(handle.raw) == 0
}
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
file_close_ffi(handle.raw) == 0
}
pub fn file_size_internal(handle : FileHandle) -> Int {
ignore(file_seek_ffi(handle.raw, 0, 2))
let size = file_tell_ffi(handle.raw)
if size < 0 {
0
} else {
size
}
}
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
file_rename_ffi(string_to_c_bytes(from_path), string_to_c_bytes(to_path)) == 0
}
pub fn remove_file_internal(path : String) -> Bool {
file_remove_ffi(string_to_c_bytes(path)) == 0
}
pub fn string_byte_length_internal(content : String) -> Int {
string_to_c_bytes(content).length() - 1
}
pub fn native_files_supported_internal() -> Bool {
true
}
+51
View File
@@ -0,0 +1,51 @@
pub struct FileHandle {
path : String
}
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
ignore(append)
ignore(path)
let _unused : FileHandle = { path: "" }
ignore(_unused)
None
}
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
ignore(handle)
ignore(content)
false
}
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
ignore(handle)
false
}
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
ignore(handle)
false
}
pub fn file_size_internal(handle : FileHandle) -> Int {
ignore(handle)
0
}
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
ignore(from_path)
ignore(to_path)
false
}
pub fn remove_file_internal(path : String) -> Bool {
ignore(path)
false
}
pub fn string_byte_length_internal(content : String) -> Int {
content.length()
}
pub fn native_files_supported_internal() -> Bool {
false
}
+7
View File
@@ -4,3 +4,10 @@ import {
"moonbitlang/core/json", "moonbitlang/core/json",
"moonbitlang/core/ref", "moonbitlang/core/ref",
} }
options(
targets: {
"file_backend_native.mbt": [ "native", "llvm" ],
"file_backend_stub.mbt": [ "js", "wasm", "wasm-gc" ],
},
)