-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5a17272
commit b8d9b93
Showing
10 changed files
with
450 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"import": [ | ||
"moonbitlang/core/string", | ||
"moonbitlang/core/builtin", | ||
"moonbitlang/core/array", | ||
"moonbitlang/core/bytes" | ||
], | ||
"targets": { | ||
"sync_io_wasm.mbt": ["wasm", "wasm-gc"], | ||
"sync_io_js.mbt": ["js"], | ||
"sync_io_native.mbt": ["native"] | ||
}, | ||
"link": { | ||
"native": { | ||
"cc-flags": "./sync_io/native_stub.c" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/stat.h> | ||
#include "moonbit.h" | ||
|
||
#ifdef _WIN32 | ||
#include <windows.h> | ||
#include <direct.h> | ||
#else | ||
#include <dirent.h> | ||
#include <unistd.h> | ||
#endif | ||
|
||
int path_exists(struct moonbit_bytes *path) { | ||
struct stat buffer; | ||
int status = stat((const char *)(path->data), &buffer); | ||
if (status == 0) { | ||
return 0; | ||
} | ||
return -1; | ||
} | ||
|
||
struct moonbit_bytes* read_file_to_bytes(struct moonbit_bytes *filename) { | ||
FILE *file = fopen((const char*)(filename->data), "rb"); | ||
if (file == NULL) { | ||
perror("fopen"); | ||
return NULL; | ||
} | ||
|
||
// move file pointer to the end of the file | ||
if (fseek(file, 0, SEEK_END) != 0) { | ||
perror("fseek"); | ||
fclose(file); | ||
return NULL; | ||
} | ||
|
||
// get the current position of the file pointer, which is the file size | ||
long size = ftell(file); | ||
if (size == -1L) { | ||
perror("ftell"); | ||
fclose(file); | ||
return NULL; | ||
} | ||
|
||
if (fseek(file, 0, SEEK_SET) != 0) { | ||
perror("fseek"); | ||
fclose(file); | ||
return NULL; | ||
} | ||
|
||
struct moonbit_bytes* bytes = moonbit_make_bytes(size, 0); | ||
|
||
// read the file content into the bytes->data | ||
size_t bytes_read = fread(bytes->data, 1, (size_t)size, file); | ||
if (bytes_read != (size_t)size) { | ||
perror("fread"); | ||
fclose(file); | ||
return NULL; | ||
} | ||
|
||
// close the file | ||
if (fclose(file) != 0) { | ||
perror("fclose"); | ||
return NULL; | ||
} | ||
|
||
return bytes; | ||
} | ||
|
||
void write_bytes_to_file(struct moonbit_bytes* path, struct moonbit_bytes* content) { | ||
FILE *file = fopen((const char *)(path->data), "wb"); | ||
size_t content_size = Moonbit_array_length(content); | ||
fwrite(content->data, 1, content_size, file); | ||
fflush(file); | ||
fclose(file); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2025 International Digital Economy Academy | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
///| | ||
type! IOError { | ||
NotFound(String) | ||
} | ||
|
||
///| | ||
impl Show for IOError with output(self, logger) { | ||
logger.write_string(self.to_string()) | ||
} | ||
|
||
///| | ||
fn IOError::to_string(self : IOError) -> String { | ||
match self { | ||
IOError::NotFound(path) => "`\{path}` does not exist" | ||
} | ||
} | ||
|
||
///| Writes an array of bytes to a file at the specified path. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `path` : The path to the file where the bytes will be written. | ||
/// - `content` : An array of bytes to be written to the file. | ||
pub fn write_bytes_to_file(path~ : String, content~ : Bytes) -> Unit { | ||
write_bytes_to_file_internal(path, content) | ||
} | ||
|
||
///| Reads the content of a file specified by the given path and returns its | ||
/// content as an array of bytes. If the file does not exist, an error is raised. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `path` : The path to the file to be read. | ||
/// | ||
/// # Returns | ||
/// | ||
/// - An array of bytes representing the content of the file. | ||
pub fn read_file_to_bytes(path~ : String) -> Bytes! { | ||
read_file_to_bytes_internal!(path) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package moonbitlang/core/sync_io | ||
|
||
// Values | ||
fn read_file_to_bytes(path~ : String) -> Bytes! | ||
|
||
fn write_bytes_to_file(path~ : String, content~ : Bytes) -> Unit | ||
|
||
// Types and methods | ||
type IOError | ||
|
||
// Type aliases | ||
|
||
// Traits | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2025 International Digital Economy Academy | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
///| | ||
fn read_file_to_bytes_internal(path : String) -> Bytes! { | ||
guard path_exists_internal(path) else { raise IOError::NotFound(path) } | ||
Bytes::from_iter(read_file_to_bytes_ffi(path).iter()) | ||
} | ||
|
||
///| | ||
extern "js" fn read_file_to_bytes_ffi(path : String) -> FixedArray[Byte] = | ||
#| function(path) { | ||
#| fs = require('fs'); | ||
#| let content = fs.readFileSync(path); | ||
#| return content; | ||
#| } | ||
|
||
///| | ||
fn write_bytes_to_file_internal(path : String, content : Bytes) -> Unit { | ||
write_bytes_to_file_ffi(path, FixedArray::from_iter(content.iter())) | ||
} | ||
|
||
///| | ||
extern "js" fn write_bytes_to_file_ffi( | ||
path : String, | ||
content : FixedArray[Byte] | ||
) = | ||
#| function(path, content) { | ||
#| fs = require('fs'); | ||
#| fs.writeFileSync(path, Buffer.from(content)); | ||
#| } | ||
|
||
///| | ||
fn path_exists_internal(path : String) -> Bool { | ||
path_exists_ffi(path) | ||
} | ||
|
||
///| | ||
extern "js" fn path_exists_ffi(path : String) -> Bool = | ||
#| function(path) { | ||
#| fs = require('fs'); | ||
#| return fs.existsSync(path); | ||
#| } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright 2025 International Digital Economy Academy | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
///| | ||
fn read_file_to_bytes_internal(path : String) -> Bytes! { | ||
guard path_exists_internal(path) else { raise IOError::NotFound(path) } | ||
let path_bytes = mbt_string_to_utf8_bytes(path, true) | ||
read_file_to_bytes_ffi(path_bytes) | ||
} | ||
|
||
///| | ||
extern "C" fn read_file_to_bytes_ffi(path : Bytes) -> Bytes = "read_file_to_bytes" | ||
|
||
///| | ||
fn write_bytes_to_file_internal(path : String, content : Bytes) -> Unit { | ||
let path_bytes = mbt_string_to_utf8_bytes(path, true) | ||
write_bytes_to_file_ffi(path_bytes, content) | ||
} | ||
|
||
///| | ||
extern "C" fn write_bytes_to_file_ffi(path : Bytes, content : Bytes) = "write_bytes_to_file" | ||
|
||
///| | ||
fn path_exists_internal(path : String) -> Bool { | ||
path_exists_ffi(mbt_string_to_utf8_bytes(path, true)) == 0 | ||
} | ||
|
||
///| | ||
extern "C" fn path_exists_ffi(path : Bytes) -> Int = "path_exists" | ||
|
||
///| | ||
fn mbt_string_to_utf8_bytes(str : String, is_c_str : Bool) -> Bytes { | ||
let res : Array[Byte] = [] | ||
let len = str.length() | ||
let mut i = 0 | ||
while i < len { | ||
let mut c = str[i].to_int() | ||
if 0xD800 <= c && c <= 0xDBFF { | ||
c -= 0xD800 | ||
i = i + 1 | ||
let l = str[i].to_int() - 0xDC00 | ||
c = (c << 10) + l + 0x10000 | ||
} | ||
|
||
// stdout accepts UTF-8, so convert the stream to UTF-8 first | ||
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 | ||
} | ||
if is_c_str { | ||
res.push((0).to_byte()) | ||
} | ||
Bytes::from_array(res) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright 2025 International Digital Economy Academy | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
test "write_and_read" { | ||
let path = "./sync_io/test.txt" | ||
let content = "Hello, World!".to_bytes() | ||
@sync_io.write_bytes_to_file(path~, content~) | ||
let byte = @sync_io.read_file_to_bytes!(path~) | ||
inspect!(byte.to_unchecked_string(), content="Hello, World!") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright 2025 International Digital Economy Academy | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
///| | ||
fn read_file_to_bytes_internal(path : String) -> Bytes! { | ||
guard path_exists_internal(path) else { raise IOError::NotFound(path) } | ||
let path = string_to_extern(path) | ||
let content = read_file_to_bytes_ffi(path) | ||
byte_array_from_extern(content) | ||
} | ||
|
||
///| | ||
fn read_file_to_bytes_ffi(path : XExternString) -> XExternByteArray = "__moonbit_fs_unstable" "read_file_to_bytes" | ||
|
||
///| | ||
fn write_bytes_to_file_internal(path : String, content : Bytes) -> Unit { | ||
let path = string_to_extern(path) | ||
let content = byte_array_to_extern(content) | ||
write_bytes_to_file_ffi(path, content) | ||
} | ||
|
||
///| | ||
fn write_bytes_to_file_ffi(path : XExternString, content : XExternByteArray) = "__moonbit_fs_unstable" "write_bytes_to_file" | ||
|
||
///| | ||
fn path_exists_internal(path : String) -> Bool { | ||
let path = string_to_extern(path) | ||
path_exists_ffi(path) | ||
} | ||
|
||
///| | ||
fn path_exists_ffi(path : XExternString) -> Bool = "__moonbit_fs_unstable" "path_exists" |
Binary file not shown.
Oops, something went wrong.