Skip to content

Commit

Permalink
feat: support native backend fs io (#69)
Browse files Browse the repository at this point in the history
* feat: support native backend fs io for unix

* internal: add fake impl for benchmark native backend

* support windows

* setup ci for msvc

* moon fmt
  • Loading branch information
Young-Flash authored Nov 5, 2024
1 parent 65705d8 commit 0a692f9
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 12 deletions.
16 changes: 9 additions & 7 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
jobs:
build:
strategy:
fail-fast: false
matrix:
os:
- name: ubuntu-latest
Expand Down Expand Up @@ -36,6 +37,10 @@ jobs:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.com/install/powershell.ps1 | iex
"C:\Users\runneradmin\.moon\bin" | Out-File -FilePath $env:GITHUB_PATH -Append
- name: Setup MSVC
if: ${{ matrix.os.name == 'windows-latest' }}
uses: ilammy/msvc-dev-cmd@v1

- name: moon version
run: |
moon version --all
Expand All @@ -51,13 +56,10 @@ jobs:
- name: moon test
run: |
# fs don't support native backend for now
moon test --target wasm
moon test --target wasm-gc
moon test --target js
moon test --target wasm --release
moon test --target wasm-gc --release
moon test --target js --release
moon test --target all --serial --release
moon test --target all --serial
moon test --target native --release
moon test --target native
- name: format diff
run: |
Expand Down
25 changes: 25 additions & 0 deletions benchmark/internal/ffi/ffi_native.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2024 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 Instant

pub fn instant_now() -> Instant {
// no implement now
panic()
}

pub fn instant_elapsed_as_secs_f64(_x : Instant) -> Double {
// no implement now
panic()
}
3 changes: 2 additions & 1 deletion benchmark/internal/ffi/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"targets": {
"ffi_wasm.mbt": ["wasm", "wasm-gc"],
"ffi_js.mbt": ["js"]
"ffi_js.mbt": ["js"],
"ffi_native.mbt": ["native"]
}
}
1 change: 1 addition & 0 deletions fs/fs.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub fn read_dir(~path : String) -> Array[String]! {
}

/// Creates a directory at the specified path.
/// Note: nested directories are not supported for native backend
///
/// # Parameters
///
Expand Down
6 changes: 4 additions & 2 deletions fs/fs_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ test "path_exist" {
}

test "create_and_remove_dir" {
@fs.create_dir(path="hello/1/12.txt")
assert_true!(@fs.path_exists(path="hello/1/12.txt"))
@fs.create_dir(path="hello")
assert_true!(@fs.path_exists(path="hello"))
assert_true!(@fs.is_dir!(path="hello"))
assert_false!(@fs.is_file!(path="hello"))
@fs.remove_dir!(path="hello")
assert_false!(@fs.path_exists(path="hello"))
try {
Expand Down
164 changes: 164 additions & 0 deletions fs/internal/ffi/fs_native.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright 2024 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.

pub fn read_file_to_string(path : String) -> String {
let path_bytes = mbt_string_to_utf8_bytes(path)
let res = read_file_to_bytes_ffi(path_bytes)
utf8_bytes_to_mbt_string(res)
}

pub fn read_file_to_bytes(path : String) -> Bytes {
let path_bytes = mbt_string_to_utf8_bytes(path)
read_file_to_bytes_ffi(path_bytes)
}

extern "C" fn read_file_to_bytes_ffi(path : Bytes) -> Bytes = "read_file_to_bytes"

pub fn write_string_to_file(path : String, content : String) -> Unit {
let path_bytes = mbt_string_to_utf8_bytes(path)
let content_bytes = mbt_string_to_utf8_bytes(content)
write_bytes_to_file_ffi(path_bytes, content_bytes)
}

pub fn write_bytes_to_file(path : String, content : Bytes) -> Unit {
let path = mbt_string_to_utf8_bytes(path)
write_bytes_to_file_ffi(path, content)
}

extern "C" fn write_bytes_to_file_ffi(path : Bytes, content : Bytes) = "write_bytes_to_file"

pub fn path_exists(path : String) -> Bool {
path_exists_ffi(mbt_string_to_utf8_bytes(path)) == 0
}

extern "C" fn path_exists_ffi(path : Bytes) -> Int = "path_exists"

pub fn read_dir(path : String) -> Array[String] {
let path_bytes = mbt_string_to_utf8_bytes(path)
let res = read_dir_ffi(path_bytes).map(utf8_bytes_to_mbt_string)
Array::from_fixed_array(res)
}

extern "C" fn read_dir_ffi(path : Bytes) -> FixedArray[Bytes] = "read_dir"

pub fn create_dir(path : String) -> Unit {
let path_bytes = mbt_string_to_utf8_bytes(path)
create_dir_ffi(path_bytes)
}

extern "C" fn create_dir_ffi(path : Bytes) = "create_dir"

pub fn is_dir(path : String) -> Bool {
let path_bytes = mbt_string_to_utf8_bytes(path)
is_dir_ffi(path_bytes) == 0
}

extern "C" fn is_dir_ffi(path : Bytes) -> Int = "is_dir"

pub fn is_file(path : String) -> Bool {
let path_bytes = mbt_string_to_utf8_bytes(path)
is_file_ffi(path_bytes) == 0
}

extern "C" fn is_file_ffi(path : Bytes) -> Int = "is_file"

pub fn remove_dir(path : String) -> Unit {
remove_dir_ffi(mbt_string_to_utf8_bytes(path))
}

extern "C" fn remove_dir_ffi(path : Bytes) = "remove_dir"

pub fn remove_file(path : String) -> Unit {
let path_bytes = mbt_string_to_utf8_bytes(path)
remove_file_ffi(path_bytes)
}

extern "C" fn remove_file_ffi(path : Bytes) = "remove_file"

fn mbt_string_to_utf8_bytes(str : String) -> 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
}
res.push((0).to_byte())
Bytes::from_array(res)
}

fn utf8_bytes_to_mbt_string(bytes : Bytes) -> String {
let res : Array[Char] = []
let len = bytes.length()
let mut i = 0
while i < len {
let mut c = bytes[i].to_int()
if c < 0x80 {
res.push(Char::from_int(c))
i += 1
} else if c < 0xE0 {
if i + 1 >= len {
break
}
c = ((c & 0x1F) << 6) | (bytes[i + 1].to_int() & 0x3F)
res.push(Char::from_int(c))
i += 2
} else if c < 0xF0 {
if i + 2 >= len {
break
}
c = ((c & 0x0F) << 12) |
((bytes[i + 1].to_int() & 0x3F) << 6) |
(bytes[i + 2].to_int() & 0x3F)
res.push(Char::from_int(c))
i += 3
} else {
if i + 3 >= len {
break
}
c = ((c & 0x07) << 18) |
((bytes[i + 1].to_int() & 0x3F) << 12) |
((bytes[i + 2].to_int() & 0x3F) << 6) |
(bytes[i + 3].to_int() & 0x3F)
c -= 0x10000
res.push(Char::from_int((c >> 10) + 0xD800))
res.push(Char::from_int((c & 0x3FF) + 0xDC00))
i += 4
}
}
String::from_array(res)
}
3 changes: 2 additions & 1 deletion fs/internal/ffi/moon.pkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"byte_array_wasm.mbt": ["wasm", "wasm-gc"],
"dir_wasm.mbt": ["wasm", "wasm-gc"],
"fs_wasm.mbt": ["wasm", "wasm-gc"],
"fs_js.mbt": ["js"]
"fs_js.mbt": ["js"],
"fs_native.mbt": ["native"]
}
}
Loading

0 comments on commit 0a692f9

Please sign in to comment.