This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 84fcc61d0 feat(binding/ocaml): Add support for operator reader and
metadata (#2881)
84fcc61d0 is described below
commit 84fcc61d0986f5a0ffc4e584821ddddecf24e346
Author: ran <[email protected]>
AuthorDate: Sun Aug 20 21:53:27 2023 +0800
feat(binding/ocaml): Add support for operator reader and metadata (#2881)
* add metadata and operator reader
* format code
* update reader seek api
* make lint happy
---
bindings/ocaml/build.rs | 4 ++
bindings/ocaml/lib/operator.ml | 26 +++++++++
bindings/ocaml/lib/operator.mli | 60 ++++++++++++++++++++
bindings/ocaml/src/lib.rs | 1 +
bindings/ocaml/src/operator.ml | 25 +++++++-
bindings/ocaml/src/operator.mli | 25 +++++++-
bindings/ocaml/{build.rs => src/operator/_type.rs} | 21 ++++---
bindings/ocaml/src/operator/metadata.rs | 66 ++++++++++++++++++++++
bindings/ocaml/src/operator/mod.rs | 27 +++++++--
.../ocaml/{build.rs => src/operator/reader.rs} | 21 +++++--
bindings/ocaml/src/seek_from.ml | 27 +++++++++
bindings/ocaml/src/seek_from.mli | 27 +++++++++
bindings/ocaml/src/seek_from/mod.rs | 58 +++++++++++++++++++
bindings/ocaml/test/test.ml | 26 +++++++++
14 files changed, 395 insertions(+), 19 deletions(-)
diff --git a/bindings/ocaml/build.rs b/bindings/ocaml/build.rs
index 9b35ddef4..de16a9e2f 100644
--- a/bindings/ocaml/build.rs
+++ b/bindings/ocaml/build.rs
@@ -19,6 +19,10 @@ use std::path::PathBuf;
pub fn main() -> std::io::Result<()> {
let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
+
+ ocaml_build::Sigs::new("src/seek_from.ml")
+ .with_source_dir(root.join("src/seek_from"))
+ .generate()?;
ocaml_build::Sigs::new("src/operator.ml")
.with_source_dir(root.join("src/operator"))
.generate()
diff --git a/bindings/ocaml/lib/operator.ml b/bindings/ocaml/lib/operator.ml
index ccd6ec29d..a22a09d24 100644
--- a/bindings/ocaml/lib/operator.ml
+++ b/bindings/ocaml/lib/operator.ml
@@ -18,12 +18,38 @@
*)
let new_operator = Opendal_core.Operator.operator
+let stat = Opendal_core.Operator.blocking_stat
let is_exist = Opendal_core.Operator.blocking_is_exist
let create_dir = Opendal_core.Operator.blocking_create_dir
let read = Opendal_core.Operator.blocking_read
+let reader = Opendal_core.Operator.blocking_reader
let write = Opendal_core.Operator.blocking_write
let copy = Opendal_core.Operator.blocking_copy
let rename = Opendal_core.Operator.blocking_rename
let delete = Opendal_core.Operator.blocking_delete
let remove = Opendal_core.Operator.blocking_remove
let remove_all = Opendal_core.Operator.blocking_remove_all
+
+module Reader = struct
+ let read = Opendal_core.Operator.reader_read
+
+ let seek reader pos mode =
+ let inner_pos =
+ match mode with
+ | Unix.SEEK_CUR -> Opendal_core.Seek_from.Current pos
+ | Unix.SEEK_END -> Opendal_core.Seek_from.End pos
+ | Unix.SEEK_SET -> Opendal_core.Seek_from.Start pos
+ in
+ Opendal_core.Operator.reader_seek reader inner_pos
+end
+
+module Metadata = struct
+ let is_file = Opendal_core.Operator.metadata_is_file
+ let is_dir = Opendal_core.Operator.metadata_is_dir
+ let content_length = Opendal_core.Operator.metadata_content_length
+ let content_md5 = Opendal_core.Operator.metadata_content_md5
+ let content_type = Opendal_core.Operator.metadata_content_type
+ let content_disposition = Opendal_core.Operator.metadata_content_disposition
+ let etag = Opendal_core.Operator.metadata_etag
+ let last_modified = Opendal_core.Operator.metadata_last_modified
+end
diff --git a/bindings/ocaml/lib/operator.mli b/bindings/ocaml/lib/operator.mli
index b94434c5b..e2493b89c 100644
--- a/bindings/ocaml/lib/operator.mli
+++ b/bindings/ocaml/lib/operator.mli
@@ -28,6 +28,17 @@ val new_operator :
@return The block operator
*)
+val stat :
+ Opendal_core.Operator.operator ->
+ string ->
+ (Opendal_core.Operator.metadata, string) result
+(** [is_exist operator path] Get current path's metadata **without cache**
directly.
+
+ @param operator The operator
+ @param path want to stat
+ @return metadata
+*)
+
val is_exist : Opendal_core.Operator.operator -> string -> (bool, string)
result
(** [is_exist operator path] Check if this path exists or not.
@@ -63,6 +74,17 @@ val read :
@return data of path
*)
+val reader :
+ Opendal_core.Operator.operator ->
+ string ->
+ (Opendal_core.Operator.reader, string) result
+(** [read operator path] Create a new reader which can read the whole path.
+
+ @param operator The operator
+ @param path want to read
+ @return reader
+*)
+
val write :
Opendal_core.Operator.operator -> string -> bytes -> (unit, string) result
(** [write operator path data] Write bytes into given path.
@@ -117,3 +139,41 @@ val remove_all :
@param operator The block operator
@param path file path
*)
+
+module Reader : sig
+ val read : Opendal_core.Operator.reader -> bytes -> (int, string) result
+ (** [read reader buf] Read data to [buf] and return data size.*)
+
+ val seek :
+ Opendal_core.Operator.reader ->
+ int64 ->
+ Unix.seek_command ->
+ (int64, string) result
+ (** [seek reader pos mode] is a function that seeks data to the given
position [pos].*)
+end
+
+module Metadata : sig
+ val is_file : Opendal_core.Operator.metadata -> bool
+ (** [is_file metadata] Returns `true` if this metadata is for a file.*)
+
+ val is_dir : Opendal_core.Operator.metadata -> bool
+ (** [is_dir metadata] Returns `true` if this metadata is for a directory.*)
+
+ val content_length : Opendal_core.Operator.metadata -> int64
+ (** [content_length metadata] Content length of this entry.*)
+
+ val content_md5 : Opendal_core.Operator.metadata -> string option
+ (** [content_md5 metadata] Content MD5 of this entry.*)
+
+ val content_type : Opendal_core.Operator.metadata -> string option
+ (** [content_type metadata] Content Type of this entry.*)
+
+ val content_disposition : Opendal_core.Operator.metadata -> string option
+ (** [content_disposition metadata] Content-Disposition of this entry*)
+
+ val etag : Opendal_core.Operator.metadata -> string option
+ (** [etag metadata] ETag of this entry.*)
+
+ val last_modified : Opendal_core.Operator.metadata -> int64 option
+ (** [last_modified metadata] Last modified of this entry.*)
+end
diff --git a/bindings/ocaml/src/lib.rs b/bindings/ocaml/src/lib.rs
index f6ec3f2b8..a69c584f4 100644
--- a/bindings/ocaml/src/lib.rs
+++ b/bindings/ocaml/src/lib.rs
@@ -22,6 +22,7 @@ use std::str::FromStr;
use ::opendal as od;
mod operator;
+mod seek_from;
pub fn new_operator(
scheme_str: String,
diff --git a/bindings/ocaml/src/operator.ml b/bindings/ocaml/src/operator.ml
index daa339786..d911209b0 100644
--- a/bindings/ocaml/src/operator.ml
+++ b/bindings/ocaml/src/operator.ml
@@ -2,16 +2,39 @@
open! Bigarray
-(* file: mod.rs *)
+(* file: _type.rs *)
type operator
+type reader
+type metadata
+
+(* file: metadata.rs *)
+
+external metadata_is_file: metadata -> bool = "metadata_is_file"
+external metadata_is_dir: metadata -> bool = "metadata_is_dir"
+external metadata_content_length: metadata -> int64 =
"metadata_content_length"
+external metadata_content_md5: metadata -> string option =
"metadata_content_md5"
+external metadata_content_type: metadata -> string option =
"metadata_content_type"
+external metadata_content_disposition: metadata -> string option =
"metadata_content_disposition"
+external metadata_etag: metadata -> string option = "metadata_etag"
+external metadata_last_modified: metadata -> int64 option =
"metadata_last_modified"
+
+(* file: mod.rs *)
+
external operator: string -> (string * string) list -> (operator, string)
Result.t = "operator"
+external blocking_stat: operator -> string -> (metadata, string) Result.t =
"blocking_stat"
external blocking_is_exist: operator -> string -> (bool, string) Result.t =
"blocking_is_exist"
external blocking_create_dir: operator -> string -> (bool, string) Result.t =
"blocking_create_dir"
external blocking_read: operator -> string -> (char array, string) Result.t =
"blocking_read"
+external blocking_reader: operator -> string -> (reader, string) Result.t =
"blocking_reader"
external blocking_write: operator -> string -> bytes -> (unit, string)
Result.t = "blocking_write"
external blocking_copy: operator -> string -> string -> (unit, string)
Result.t = "blocking_copy"
external blocking_rename: operator -> string -> string -> (unit, string)
Result.t = "blocking_rename"
external blocking_delete: operator -> string -> (unit, string) Result.t =
"blocking_delete"
external blocking_remove: operator -> string array -> (unit, string) Result.t
= "blocking_remove"
external blocking_remove_all: operator -> string -> (unit, string) Result.t =
"blocking_remove_all"
+
+(* file: reader.rs *)
+
+external reader_read: reader -> bytes -> (int, string) Result.t =
"reader_read"
+external reader_seek: reader -> Seek_from.seek_from -> (int64, string)
Result.t = "reader_seek"
diff --git a/bindings/ocaml/src/operator.mli b/bindings/ocaml/src/operator.mli
index daa339786..d911209b0 100644
--- a/bindings/ocaml/src/operator.mli
+++ b/bindings/ocaml/src/operator.mli
@@ -2,16 +2,39 @@
open! Bigarray
-(* file: mod.rs *)
+(* file: _type.rs *)
type operator
+type reader
+type metadata
+
+(* file: metadata.rs *)
+
+external metadata_is_file: metadata -> bool = "metadata_is_file"
+external metadata_is_dir: metadata -> bool = "metadata_is_dir"
+external metadata_content_length: metadata -> int64 =
"metadata_content_length"
+external metadata_content_md5: metadata -> string option =
"metadata_content_md5"
+external metadata_content_type: metadata -> string option =
"metadata_content_type"
+external metadata_content_disposition: metadata -> string option =
"metadata_content_disposition"
+external metadata_etag: metadata -> string option = "metadata_etag"
+external metadata_last_modified: metadata -> int64 option =
"metadata_last_modified"
+
+(* file: mod.rs *)
+
external operator: string -> (string * string) list -> (operator, string)
Result.t = "operator"
+external blocking_stat: operator -> string -> (metadata, string) Result.t =
"blocking_stat"
external blocking_is_exist: operator -> string -> (bool, string) Result.t =
"blocking_is_exist"
external blocking_create_dir: operator -> string -> (bool, string) Result.t =
"blocking_create_dir"
external blocking_read: operator -> string -> (char array, string) Result.t =
"blocking_read"
+external blocking_reader: operator -> string -> (reader, string) Result.t =
"blocking_reader"
external blocking_write: operator -> string -> bytes -> (unit, string)
Result.t = "blocking_write"
external blocking_copy: operator -> string -> string -> (unit, string)
Result.t = "blocking_copy"
external blocking_rename: operator -> string -> string -> (unit, string)
Result.t = "blocking_rename"
external blocking_delete: operator -> string -> (unit, string) Result.t =
"blocking_delete"
external blocking_remove: operator -> string array -> (unit, string) Result.t
= "blocking_remove"
external blocking_remove_all: operator -> string -> (unit, string) Result.t =
"blocking_remove_all"
+
+(* file: reader.rs *)
+
+external reader_read: reader -> bytes -> (int, string) Result.t =
"reader_read"
+external reader_seek: reader -> Seek_from.seek_from -> (int64, string)
Result.t = "reader_seek"
diff --git a/bindings/ocaml/build.rs b/bindings/ocaml/src/operator/_type.rs
similarity index 61%
copy from bindings/ocaml/build.rs
copy to bindings/ocaml/src/operator/_type.rs
index 9b35ddef4..0dda2e119 100644
--- a/bindings/ocaml/build.rs
+++ b/bindings/ocaml/src/operator/_type.rs
@@ -15,11 +15,18 @@
// specific language governing permissions and limitations
// under the License.
-use std::path::PathBuf;
+// For ocaml-rs, the build order in the same build group is the order of the
file names.
+// In order to use the type in the function in the generated ocaml file, it
must be defined on the first generated file.
+use super::*;
-pub fn main() -> std::io::Result<()> {
- let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
- ocaml_build::Sigs::new("src/operator.ml")
- .with_source_dir(root.join("src/operator"))
- .generate()
-}
+#[ocaml::sig]
+pub struct Operator(pub(crate) od::BlockingOperator);
+ocaml::custom!(Operator);
+
+#[ocaml::sig]
+pub struct Reader(pub(crate) od::BlockingReader);
+ocaml::custom!(Reader);
+
+#[ocaml::sig]
+pub struct Metadata(pub(crate) od::Metadata);
+ocaml::custom!(Metadata);
diff --git a/bindings/ocaml/src/operator/metadata.rs
b/bindings/ocaml/src/operator/metadata.rs
new file mode 100644
index 000000000..551df21af
--- /dev/null
+++ b/bindings/ocaml/src/operator/metadata.rs
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use super::*;
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> bool ")]
+pub fn metadata_is_file(metadata: &mut Metadata) -> bool {
+ metadata.0.is_file()
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> bool ")]
+pub fn metadata_is_dir(metadata: &mut Metadata) -> bool {
+ metadata.0.is_dir()
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> int64 ")]
+pub fn metadata_content_length(metadata: &mut Metadata) -> u64 {
+ metadata.0.content_length()
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> string option ")]
+pub fn metadata_content_md5(metadata: &mut Metadata) -> Option<String> {
+ metadata.0.content_md5().map(String::from)
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> string option ")]
+pub fn metadata_content_type(metadata: &mut Metadata) -> Option<String> {
+ metadata.0.content_type().map(String::from)
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> string option ")]
+pub fn metadata_content_disposition(metadata: &mut Metadata) -> Option<String>
{
+ metadata.0.content_disposition().map(String::from)
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> string option ")]
+pub fn metadata_etag(metadata: &mut Metadata) -> Option<String> {
+ metadata.0.etag().map(String::from)
+}
+
+#[ocaml::func]
+#[ocaml::sig("metadata -> int64 option ")]
+pub fn metadata_last_modified(metadata: &mut Metadata) -> Option<i64> {
+ metadata.0.last_modified().map(|t| t.timestamp())
+}
diff --git a/bindings/ocaml/src/operator/mod.rs
b/bindings/ocaml/src/operator/mod.rs
index 5915c916b..833cf6391 100644
--- a/bindings/ocaml/src/operator/mod.rs
+++ b/bindings/ocaml/src/operator/mod.rs
@@ -15,11 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use super::*;
+mod _type;
+mod metadata;
+mod reader;
-#[ocaml::sig]
-pub struct Operator(od::BlockingOperator);
-ocaml::custom!(Operator);
+use super::*;
+use _type::*;
#[ocaml::func]
#[ocaml::sig("string -> (string * string) list -> (operator, string) Result.t
")]
@@ -31,6 +32,15 @@ pub fn operator(
Ok(Operator(op.blocking()).into())
}
+#[ocaml::func]
+#[ocaml::sig("operator -> string -> (metadata, string) Result.t ")]
+pub fn blocking_stat(
+ operator: &mut Operator,
+ path: String,
+) -> Result<ocaml::Pointer<Metadata>, String> {
+ map_res_error(operator.0.stat(path.as_str()).map(|m| Metadata(m).into()))
+}
+
#[ocaml::func]
#[ocaml::sig("operator -> string -> (bool, string) Result.t ")]
pub fn blocking_is_exist(operator: &mut Operator, path: String) ->
Result<bool, String> {
@@ -49,6 +59,15 @@ pub fn blocking_read(operator: &mut Operator, path: String)
-> Result<Vec<u8>, S
map_res_error(operator.0.read(path.as_str()))
}
+#[ocaml::func]
+#[ocaml::sig("operator -> string -> (reader, string) Result.t ")]
+pub fn blocking_reader(
+ operator: &mut Operator,
+ path: String,
+) -> Result<ocaml::Pointer<Reader>, String> {
+ map_res_error(operator.0.reader(path.as_str())).map(|op| Reader(op).into())
+}
+
#[ocaml::func]
#[ocaml::sig("operator -> string -> bytes -> (unit, string) Result.t ")]
pub fn blocking_write(
diff --git a/bindings/ocaml/build.rs b/bindings/ocaml/src/operator/reader.rs
similarity index 61%
copy from bindings/ocaml/build.rs
copy to bindings/ocaml/src/operator/reader.rs
index 9b35ddef4..bb75f7b38 100644
--- a/bindings/ocaml/build.rs
+++ b/bindings/ocaml/src/operator/reader.rs
@@ -15,11 +15,20 @@
// specific language governing permissions and limitations
// under the License.
-use std::path::PathBuf;
+use std::io;
-pub fn main() -> std::io::Result<()> {
- let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
- ocaml_build::Sigs::new("src/operator.ml")
- .with_source_dir(root.join("src/operator"))
- .generate()
+use super::*;
+
+use opendal::raw::oio::BlockingRead;
+
+#[ocaml::func]
+#[ocaml::sig("reader -> bytes -> (int, string) Result.t ")]
+pub fn reader_read(reader: &mut Reader, buf: &mut [u8]) -> Result<usize,
String> {
+ map_res_error(reader.0.read(buf))
+}
+
+#[ocaml::func]
+#[ocaml::sig("reader -> Seek_from.seek_from -> (int64, string) Result.t ")]
+pub fn reader_seek(reader: &mut Reader, pos: seek_from::SeekFrom) ->
Result<u64, String> {
+ map_res_error(reader.0.seek(io::SeekFrom::from(pos)))
}
diff --git a/bindings/ocaml/src/seek_from.ml b/bindings/ocaml/src/seek_from.ml
new file mode 100644
index 000000000..64b6f0cb9
--- /dev/null
+++ b/bindings/ocaml/src/seek_from.ml
@@ -0,0 +1,27 @@
+(* Generated by ocaml-rs *)
+
+open! Bigarray
+
+(* file: mod.rs *)
+
+type seek_from =
+| Start of int64 (**
+ [Start]: Sets the offset to the provided number of bytes.
+ *)
+
+| End of int64 (**
+ [End]: Sets the offset to the size of this object plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+
+| Current of int64 (**
+ [Current]: Sets the offset to the current position plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+
diff --git a/bindings/ocaml/src/seek_from.mli b/bindings/ocaml/src/seek_from.mli
new file mode 100644
index 000000000..64b6f0cb9
--- /dev/null
+++ b/bindings/ocaml/src/seek_from.mli
@@ -0,0 +1,27 @@
+(* Generated by ocaml-rs *)
+
+open! Bigarray
+
+(* file: mod.rs *)
+
+type seek_from =
+| Start of int64 (**
+ [Start]: Sets the offset to the provided number of bytes.
+ *)
+
+| End of int64 (**
+ [End]: Sets the offset to the size of this object plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+
+| Current of int64 (**
+ [Current]: Sets the offset to the current position plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+
diff --git a/bindings/ocaml/src/seek_from/mod.rs
b/bindings/ocaml/src/seek_from/mod.rs
new file mode 100644
index 000000000..e9b0290b3
--- /dev/null
+++ b/bindings/ocaml/src/seek_from/mod.rs
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use std::io;
+
+#[derive(ocaml::FromValue, ocaml::ToValue, Clone, Copy)]
+#[ocaml::sig(
+ "
+| Start of int64 (**
+ [Start]: Sets the offset to the provided number of bytes.
+ *)
+
+| End of int64 (**
+ [End]: Sets the offset to the size of this object plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+
+| Current of int64 (**
+ [Current]: Sets the offset to the current position plus the specified
number of
+ bytes.
+
+ It is possible to seek beyond the end of an object, but it's an error to
+ seek before byte 0.
+ *)
+"
+)]
+pub enum SeekFrom {
+ Start(u64),
+ End(i64),
+ Current(i64),
+}
+
+impl From<SeekFrom> for io::SeekFrom {
+ fn from(value: SeekFrom) -> Self {
+ match value {
+ SeekFrom::Start(v) => io::SeekFrom::Start(v),
+ SeekFrom::End(v) => io::SeekFrom::End(v),
+ SeekFrom::Current(v) => io::SeekFrom::Current(v),
+ }
+ }
+}
diff --git a/bindings/ocaml/test/test.ml b/bindings/ocaml/test/test.ml
index a92fc470b..a13e44b88 100644
--- a/bindings/ocaml/test/test.ml
+++ b/bindings/ocaml/test/test.ml
@@ -58,6 +58,30 @@ let test_copy_and_read test_ctxt =
let got_res = test_check_result (Operator.read bo "bar") in
assert_equal data (got_res |> Array.to_seq |> Bytes.of_seq |>
Bytes.to_string)
+let test_operator_reader test_ctxt =
+ let bo = new_test_block_operator test_ctxt in
+ ignore
+ (test_check_result
+ (Operator.write bo "tempfile" (Bytes.of_string "helloworld")));
+ let reader = Operator.reader bo "tempfile" |> test_check_result in
+ let s = Operator.Reader.seek reader 5L SEEK_CUR |> test_check_result in
+ assert_equal 5 (Int64.to_int s);
+ let data = Bytes.create 5 in
+ let i = Operator.Reader.read reader data |> test_check_result in
+ assert_equal 5 i;
+ assert_equal "world" (Bytes.to_string data)
+
+let test_operator_stat test_ctxt =
+ let bo = new_test_block_operator test_ctxt in
+ ignore
+ (test_check_result
+ (Operator.write bo "tempfile" (Bytes.of_string "helloworld")));
+ let metadata = Operator.stat bo "tempfile" |> test_check_result in
+ assert_equal false (Operator.Metadata.is_dir metadata);
+ assert_equal true (Operator.Metadata.is_file metadata);
+ assert_equal 10L (Operator.Metadata.content_length metadata);
+ ()
+
let suite =
"suite"
>::: [
@@ -65,6 +89,8 @@ let suite =
"test_create_dir_and_remove_all" >:: test_create_dir_and_remove_all;
"test_block_write_and_read" >:: test_block_write_and_read;
"test_copy_and_read" >:: test_copy_and_read;
+ "test_operator_reader" >:: test_operator_reader;
+ "test_operator_stat" >:: test_operator_stat;
]
let () = run_test_tt_main suite