Skip to content

Commit 7668101

Browse files
committed
feat: add fs_sync package
1 parent 133e21a commit 7668101

File tree

7 files changed

+225
-0
lines changed

7 files changed

+225
-0
lines changed

fs_sync/blackbox_test.mbt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2025 International Digital Economy Academy
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
test "write_and_read" {
16+
let path_1 = "./fs_sync/test_1.txt"
17+
let path_2 = "./fs_sync/test_2.txt"
18+
let content_1 = "Hello, World"
19+
let content_2 = "Hello, MoonBit"
20+
@fs_sync.write_bytes_to_file!(path_1, content_1.to_bytes())
21+
let res_1 = @fs_sync.read_file_to_bytes!(path_1)
22+
inspect!(res_1.to_unchecked_string(), content=content_1)
23+
24+
@fs_sync.write_string_to_file!(path_2, content_2)
25+
let res_2 = @fs_sync.read_file_to_string!(path_2)
26+
inspect!(res_2, content=content_2)
27+
}

fs_sync/fs_sync.mbt

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025 International Digital Economy Academy
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
///|
16+
pub type! IOError String derive(Show)
17+
18+
///| Reads the content of a file specified by the given path and returns its
19+
/// content as `Bytes`
20+
///
21+
/// # Parameters
22+
///
23+
/// - `path` : The path to the file to be read.
24+
///
25+
/// # Returns
26+
///
27+
/// - A `Bytes` representing the content of the file.
28+
pub fn read_file_to_bytes(path: String) -> Bytes! {
29+
read_file_to_bytes_internal!(path)
30+
}
31+
32+
///| Reads the content of a file specified by the given path and returns its
33+
/// content as `String`.
34+
///
35+
/// # Parameters
36+
///
37+
/// - `path` : The path to the file to be read.
38+
/// - `encoding~` : The encoding of the file. Only support `utf8` for now.
39+
///
40+
/// # Returns
41+
///
42+
/// - A `String` representing the content of the file.
43+
pub fn read_file_to_string(path: String, encoding~ : String = "utf8") -> String! {
44+
read_file_to_string_internal!(path, encoding~)
45+
}
46+
47+
///| Writes a `Bytes` to a file at the specified path.
48+
///
49+
/// # Parameters
50+
///
51+
/// - `path` : The path to the file where the bytes will be written.
52+
/// - `content` : A `Bytes` to be written to the file.
53+
pub fn write_bytes_to_file(path: String, content: Bytes) -> Unit! {
54+
write_bytes_to_file_internal!(path, content)
55+
}
56+
57+
///| Writes a `String` to a file at the specified path.
58+
///
59+
/// # Parameters
60+
///
61+
/// - `path` : The path to the file where the string will be written.
62+
/// - `content` : A `String` to be written to the file.
63+
/// - `encoding~` : The encoding of the file. Only support `utf8` for now.
64+
pub fn write_string_to_file(path: String, content: String, encoding~ : String = "utf8") -> Unit! {
65+
write_string_to_file_internal!(path, content, encoding~)
66+
}

fs_sync/fs_sync.mbti

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package moonbitlang/core/fs_sync
2+
3+
// Values
4+
fn read_file_to_bytes(String) -> Bytes!
5+
6+
fn read_file_to_string(String, encoding~ : String = ..) -> String!
7+
8+
fn write_bytes_to_file(String, Bytes) -> Unit!
9+
10+
fn write_string_to_file(String, String, encoding~ : String = ..) -> Unit!
11+
12+
// Types and methods
13+
pub type! IOError String
14+
impl Show for IOError
15+
16+
// Type aliases
17+
18+
// Traits
19+

fs_sync/moon.pkg.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"import": [
3+
"moonbitlang/core/string",
4+
"moonbitlang/core/builtin",
5+
"moonbitlang/core/array",
6+
"moonbitlang/core/bytes"
7+
],
8+
"targets": {
9+
"fs_sync_wasm.mbt": ["wasm", "wasm-gc"],
10+
"fs_sync_js.mbt": ["js"],
11+
"fs_sync_native.mbt": ["native"]
12+
},
13+
"link": {
14+
"native": {
15+
"cc-flags": "-O2"
16+
}
17+
}
18+
}

fs_sync/test_1.txt

24 Bytes
Binary file not shown.

fs_sync/test_2.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello, MoonBit

fs_sync/util.mbt

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2025 International Digital Economy Academy
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
///|
17+
fn mbt_string_to_utf8_bytes(str : String, is_c_str : Bool) -> Bytes {
18+
let res : Array[Byte] = []
19+
let len = str.length()
20+
let mut i = 0
21+
while i < len {
22+
let mut c = str[i].to_int()
23+
if 0xD800 <= c && c <= 0xDBFF {
24+
c -= 0xD800
25+
i = i + 1
26+
let l = str[i].to_int() - 0xDC00
27+
c = (c << 10) + l + 0x10000
28+
}
29+
30+
// stdout accepts UTF-8, so convert the stream to UTF-8 first
31+
if c < 0x80 {
32+
res.push(c.to_byte())
33+
} else if c < 0x800 {
34+
res.push((0xc0 + (c >> 6)).to_byte())
35+
res.push((0x80 + (c & 0x3f)).to_byte())
36+
} else if c < 0x10000 {
37+
res.push((0xe0 + (c >> 12)).to_byte())
38+
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
39+
res.push((0x80 + (c & 0x3f)).to_byte())
40+
} else {
41+
res.push((0xf0 + (c >> 18)).to_byte())
42+
res.push((0x80 + ((c >> 12) & 0x3f)).to_byte())
43+
res.push((0x80 + ((c >> 6) & 0x3f)).to_byte())
44+
res.push((0x80 + (c & 0x3f)).to_byte())
45+
}
46+
i = i + 1
47+
}
48+
if is_c_str {
49+
res.push((0).to_byte())
50+
}
51+
Bytes::from_array(res)
52+
}
53+
54+
fn utf8_bytes_to_mbt_string(bytes : Bytes) -> String {
55+
let res : Array[Char] = []
56+
let len = bytes.length()
57+
let mut i = 0
58+
while i < len {
59+
let mut c = bytes[i].to_int()
60+
if c < 0x80 {
61+
res.push(Char::from_int(c))
62+
i += 1
63+
} else if c < 0xE0 {
64+
if i + 1 >= len {
65+
break
66+
}
67+
c = ((c & 0x1F) << 6) | (bytes[i + 1].to_int() & 0x3F)
68+
res.push(Char::from_int(c))
69+
i += 2
70+
} else if c < 0xF0 {
71+
if i + 2 >= len {
72+
break
73+
}
74+
c = ((c & 0x0F) << 12) |
75+
((bytes[i + 1].to_int() & 0x3F) << 6) |
76+
(bytes[i + 2].to_int() & 0x3F)
77+
res.push(Char::from_int(c))
78+
i += 3
79+
} else {
80+
if i + 3 >= len {
81+
break
82+
}
83+
c = ((c & 0x07) << 18) |
84+
((bytes[i + 1].to_int() & 0x3F) << 12) |
85+
((bytes[i + 2].to_int() & 0x3F) << 6) |
86+
(bytes[i + 3].to_int() & 0x3F)
87+
c -= 0x10000
88+
res.push(Char::from_int((c >> 10) + 0xD800))
89+
res.push(Char::from_int((c & 0x3FF) + 0xDC00))
90+
i += 4
91+
}
92+
}
93+
String::from_array(res)
94+
}

0 commit comments

Comments
 (0)