From: Hiroyuki_Katsura <hiroyuki.katsura.0513(a)gmail.com>
---
configure.ac | 2 +
generator/bindtests.ml | 63 +++++
generator/main.ml | 2 +-
generator/rust.ml | 423 +++++++++++++++++-----------
generator/rust.mli | 5 +-
rust/.gitignore | 2 +
rust/Makefile.am | 16 +-
rust/run-bindtests | 23 ++
rust/run-tests | 21 ++
rust/src/bin/.gitkeep | 0
rust/tests/010_load.rs | 28 +-
rust/tests/020_create.rs | 28 +-
rust/tests/030_create_flags.rs | 29 +-
rust/tests/040_create_multiple.rs | 28 +-
rust/tests/050_handle_properties.rs | 31 +-
rust/tests/070_opt_args.rs | 39 +--
rust/tests/080_version.rs | 31 +-
rust/tests/090_ret_values.rs | 61 ++++
rust/tests/100_launch.rs | 65 +++++
19 files changed, 618 insertions(+), 279 deletions(-)
create mode 100644 rust/.gitignore
create mode 100755 rust/run-bindtests
create mode 100755 rust/run-tests
create mode 100644 rust/src/bin/.gitkeep
create mode 100644 rust/tests/090_ret_values.rs
create mode 100644 rust/tests/100_launch.rs
diff --git a/configure.ac b/configure.ac
index f9bdbe54b..b35b1ce0f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -431,6 +431,8 @@ AS_ECHO_N(["Vala bindings ....................... "])
if test "x$ENABLE_VAPIGEN_TRUE" = "x"; then echo "yes";
else echo "no"; fi
AS_ECHO_N(["bash completion ..................... "])
if test "x$HAVE_BASH_COMPLETION_TRUE" = "x"; then echo
"yes"; else echo "no"; fi
+AS_ECHO_N(["Rust bindings ....................... "])
+if test "x$HAVE_RUST_TRUE" = "x"; then echo "yes"; else
echo "no"; fi
echo
echo "If any optional component is configured 'no' when you expected
'yes'"
echo "then you should check the preceding messages."
diff --git a/generator/bindtests.ml b/generator/bindtests.ml
index 41aef47ea..e88e71c8a 100644
--- a/generator/bindtests.ml
+++ b/generator/bindtests.ml
@@ -986,6 +986,69 @@ and generate_php_bindtests () =
and generate_rust_bindtests () =
generate_header CStyle GPLv2plus;
+ pr "extern crate guestfs;\n";
+ pr "use guestfs::*;\n";
+ pr "use std::default::Default;\n";
+ pr "\n";
+ pr "fn main() {\n";
+ pr " let g = match Handle::create() {\n";
+ pr " Ok(g) => g,\n";
+ pr " Err(e) => panic!(format!(\" could not create handle {}\",
e)),\n";
+ pr " };\n";
+ generate_lang_bindtests (
+ fun f args optargs ->
+ pr " g.%s(" f;
+ let needs_comma = ref false in
+ List.iter (
+ fun arg ->
+ if !needs_comma then pr ", ";
+ needs_comma := true;
+ match arg with
+ | CallString s -> pr "\"%s\"" s
+ | CallOptString None -> pr "None"
+ | CallOptString (Some s) -> pr "Some(\"%s\")" s
+ | CallStringList xs ->
+ pr "&vec![%s]"
+ (String.concat ", " (List.map (sprintf
"\"%s\"") xs))
+ | CallInt i -> pr "%d" i
+ | CallInt64 i -> pr "%Ldi64" i
+ | CallBool b -> pr "%b" b
+ | CallBuffer s ->
+ let f = fun x -> sprintf "%d" (Char.code x) in
+ pr "&[%s]"
+ (String.concat ", " (List.map f (String.explode s)))
+ ) args;
+ if !needs_comma then pr ", ";
+ (match optargs with
+ | None -> pr "Default::default()"
+ | Some optargs ->
+ pr "%sOptArgs{" (Rust.snake2caml f);
+ needs_comma := false;
+ List.iter (
+ fun optarg ->
+ if !needs_comma then pr ", ";
+ needs_comma := true;
+ match optarg with
+ | CallOBool (n, v) ->
+ pr "%s: Some(%b)" n v
+ | CallOInt (n, v) ->
+ pr "%s: Some(%d)" n v
+ | CallOInt64 (n, v) ->
+ pr "%s: Some(%Ldi64)" n v
+ | CallOString (n, v) ->
+ pr "%s: Some(\"%s\")" n v
+ | CallOStringList (n, xs) ->
+ pr "%s: Some(&[%s])"
+ n (String.concat ", " (List.map (sprintf
"\"%s\"") xs))
+ ) optargs;
+ if !needs_comma then pr ", ";
+ pr ".. Default::default()}";
+ );
+ pr ").expect(\"failed to run\");\n";
+ );
+ pr " println!(\"EOF\");\n";
+ pr "}\n";
+
(* Language-independent bindings tests - we do it this way to
* ensure there is parity in testing bindings across all languages.
*)
diff --git a/generator/main.ml b/generator/main.ml
index 5de89138c..ffe1bb95c 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -374,7 +374,7 @@ Run it from the top source directory using the command
output_to "rust/src/lib.rs"
Rust.generate_rust;
- output_to "rust/tests/bind_test.rs"
+ output_to "rust/src/bin/bindtests.rs"
Bindtests.generate_rust_bindtests;
(* Generate the list of files generated -- last. *)
diff --git a/generator/rust.ml b/generator/rust.ml
index 4766357be..ee65b1073 100644
--- a/generator/rust.ml
+++ b/generator/rust.ml
@@ -61,14 +61,16 @@ let generate_rust () =
pr "
use std::collections;
use std::convert;
+use std::convert::TryFrom;
use std::ffi;
-use std::slice;
-use std::ptr;
use std::os::raw::{c_char, c_int, c_void};
+use std::ptr;
+use std::slice;
+use std::str;
#[allow(non_camel_case_types)]
-enum guestfs_h {} // opaque struct
+enum guestfs_h {} // opaque struct
#[link(name = \"guestfs\")]
extern \"C\" {
@@ -141,22 +143,22 @@ impl CreateFlags {
}
struct NullTerminatedIter<T: Copy + Clone> {
- p: *const T
+ p: *const *const T,
}
impl<T: Copy + Clone> NullTerminatedIter<T> {
- fn new(p: *const T) -> NullTerminatedIter<T> {
- NullTerminatedIter{ p }
+ fn new(p: *const *const T) -> NullTerminatedIter<T> {
+ NullTerminatedIter { p }
}
}
impl<T: Copy + Clone> Iterator for NullTerminatedIter<T> {
- type Item = T;
- fn next(&mut self) -> Option<T> {
- if self.p.is_null() {
+ type Item = *const T;
+ fn next(&mut self) -> Option<*const T> {
+ let r = unsafe { *(self.p) };
+ if r.is_null() {
None
} else {
- let r = unsafe { *(self.p) };
self.p = unsafe { self.p.offset(1) };
Some(r)
}
@@ -171,12 +173,15 @@ struct RawList<T> {
struct RawListIter<'a, T> {
current: u32,
- list: &'a RawList<T>
+ list: &'a RawList<T>,
}
-impl<T> RawList<T> {
+impl<T> RawList<T> {
fn iter<'a>(&'a self) -> RawListIter<'a, T> {
- RawListIter{ current: 0, list: self }
+ RawListIter {
+ current: 0,
+ list: self,
+ }
}
}
@@ -193,60 +198,81 @@ impl<'a, T> Iterator for RawListIter<'a, T> {
}
}
-
-fn arg_string_list (v: &Vec<&str>) -> Vec<*const i8> {
- let length = v.len();
+fn arg_string_list(v: &[&str]) -> Result<Vec<ffi::CString>, Error>
{
let mut w = Vec::new();
for x in v.iter() {
let y: &str = x;
- let s = ffi::CString::new(y).unwrap();
- w.push(s.as_ptr());
+ w.push(ffi::CString::new(y)?);
+ }
+ Ok(w)
+}
+
+fn free_string_list(l: *const *const c_char) {
+ for buf in NullTerminatedIter::new(l) {
+ unsafe { free(buf as * const c_void) };
}
- w.push(ptr::null());
- w
+ unsafe { free(l as *const c_void) };
}
-fn hashmap (l: *const *const c_char) -> collections::HashMap<String, String> {
+fn hashmap(l: *const *const c_char) -> Result<collections::HashMap<String,
String>, Error> {
let mut map = collections::HashMap::new();
let mut iter = NullTerminatedIter::new(l);
while let Some(key) = iter.next() {
if let Some(val) = iter.next() {
- let key = unsafe { ffi::CStr::from_ptr(key) }.to_str().unwrap();
- let val = unsafe { ffi::CStr::from_ptr(val) }.to_str().unwrap();
+ let key = unsafe { ffi::CStr::from_ptr(key) }.to_str()?;
+ let val = unsafe { ffi::CStr::from_ptr(val) }.to_str()?;
map.insert(key.to_string(), val.to_string());
} else {
+ // Internal Error -> panic
panic!(\"odd number of items in hash table\");
}
}
- map
+ Ok(map)
}
-fn struct_list<T, S: convert::From<*const T>>(l: *const RawList<T>)
-> Vec<S> {
+fn struct_list<T, S: TryFrom<*const T, Error = Error>>(
+ l: *const RawList<T>,
+) -> Result<Vec<S>, Error> {
let mut v = Vec::new();
- for x in unsafe {&*l}.iter() {
- v.push(S::from(x));
+ for x in unsafe { &*l }.iter() {
+ v.push(S::try_from(x)?);
}
- v
+ Ok(v)
}
-fn string_list (l: *const *const c_char) -> Vec<String> {
+fn string_list(l: *const *const c_char) -> Result<Vec<String>, Error> {
let mut v = Vec::new();
for x in NullTerminatedIter::new(l) {
- let s = unsafe { ffi::CStr::from_ptr(x) }.to_str().unwrap();
+ let s = unsafe { ffi::CStr::from_ptr(x) }.to_str()?;
v.push(s.to_string());
}
- v
-}
-
-fn free_string_list(l: *const *const c_char) {
- // TODO
+ Ok(v)
}
#[derive(Debug)]
-pub struct Error {
+pub struct APIError {
operation: &'static str,
message: String,
- errno: i32
+ errno: i32,
+}
+
+#[derive(Debug)]
+pub enum Error {
+ API(APIError),
+ IllegalString(ffi::NulError),
+ Utf8Error(str::Utf8Error),
+}
+
+impl convert::From<ffi::NulError> for Error {
+ fn from(error: ffi::NulError) -> Self {
+ Error::IllegalString(error)
+ }
+}
+
+impl convert::From<str::Utf8Error> for Error {
+ fn from(error: str::Utf8Error) -> Self {
+ Error::Utf8Error(error)
+ }
}
impl Handle {
@@ -271,13 +297,17 @@ impl Handle {
fn get_error_from_handle(&self, operation: &'static str) -> Error {
let c_msg = unsafe { guestfs_last_error(self.g) };
let message = unsafe { ffi::CStr::from_ptr(c_msg).to_str().unwrap().to_string()
};
- let errno = unsafe { guestfs_last_errno(self.g) } ;
- Error { operation, message, errno }
+ let errno = unsafe { guestfs_last_errno(self.g) };
+ Error::API(APIError {
+ operation,
+ message,
+ errno,
+ })
}
}
pub struct UUID {
- uuid: [u8; 32]
+ uuid: [u8; 32],
}
impl UUID {
@@ -288,7 +318,6 @@ impl UUID {
self.uuid
}
}
-
";
List.iter (
fun { s_camel_name = name; s_name = c_name; s_cols = cols } ->
@@ -325,22 +354,24 @@ impl UUID {
) cols;
pr "}\n";
pr "\n";
- pr "impl convert::From<*const Raw%s> for %s {\n" name name;
- pr " fn from(raw: *const Raw%s) -> Self {\n" name;
- pr " unsafe { %s {\n" name;
+ pr "impl TryFrom<*const Raw%s> for %s {\n" name name;
+ pr " type Error = Error;\n";
+ pr " fn try_from(raw: *const Raw%s) -> Result<Self, Self::Error>
{\n" name;
+ pr " Ok(unsafe {\n";
+ pr " %s {\n" name;
List.iter (
fun x ->
- indent 3;
+ indent 4;
match x with
| n, FChar ->
pr "%s: (*raw).%s as i8,\n" n n;
| n, FString ->
pr "%s: {\n" n;
- indent 4;
+ indent 5;
pr "let s = ffi::CStr::from_ptr((*raw).%s);\n" n;
+ indent 5;
+ pr "s.to_str()?.to_string()\n";
indent 4;
- pr "s.to_str().unwrap().to_string()\n";
- indent 3;
pr "},\n"
| n, FBuffer ->
pr "%s: slice::from_raw_parts((*raw).%s as *const u8,
(*raw).%s_len).to_vec(),\n" n n n
@@ -349,9 +380,14 @@ impl UUID {
| n, (FUInt32 | FInt32 | FUInt64 | FInt64 | FBytes) ->
pr "%s: (*raw).%s,\n" n n
| n, FOptPercent ->
- pr "%s: if (*raw).%s < 0.0 { None } else { Some((*raw).%s) },\n"
n n n
+ pr "%s: if (*raw).%s < 0.0 {\n" n n;
+ indent 4; pr " None\n";
+ indent 4; pr "} else {\n";
+ indent 4; pr " Some((*raw).%s)\n" n;
+ indent 4; pr"},\n"
) cols;
- pr " } }\n";
+ pr " }\n";
+ pr " })\n";
pr " }\n";
pr "}\n"
) external_structs;
@@ -361,11 +397,26 @@ impl UUID {
pr "extern \"C\" {\n";
List.iter (
fun { s_camel_name = name; s_name = c_name; } ->
- pr "fn guestfs_free_%s(v: *const Raw%s);\n" c_name name;
- pr "fn guestfs_free_%s_list(l: *const RawList<Raw%s>);\n" c_name
name;
+ pr " #[allow(dead_code)]\n";
+ pr " fn guestfs_free_%s(v: *const Raw%s);\n" c_name name;
+ pr " #[allow(dead_code)]\n";
+ pr " fn guestfs_free_%s_list(l: *const RawList<Raw%s>);\n"
c_name name;
) external_structs;
pr "}\n";
+ (* [Outline] There are three types for each optional structs: SOptArgs,
+ * CExprSOptArgs, RawSOptArgs.
+ * SOptArgs: for Rust bindings' API. This can be seen by bindings' users.
+ * CExprSOptArgs: Each field has C expression(e.g. CString, *const c_char)
+ * RawSOptArgs: Each field has raw pointers or integer values
+ *
+ * SOptArgs ---try_into()---> CExprSOptArgs ---to_raw()---> RawSOptArgs
+ *
+ * Note: direct translation from SOptArgs to RawSOptArgs will cause a memory
+ * management problem. Using into_raw/from_raw, this problem can be avoided,
+ * but it is complex to handle freeing memories manually in Rust because of
+ * panic/?/etc.
+ *)
(* generate structs for optional arguments *)
List.iter (
@@ -383,27 +434,75 @@ impl UUID {
pr "\n";
pr "/* Optional Structs */\n";
pr "#[derive(Default)]\n";
- pr "pub struct OptArgs%s%s {\n" cname opt_life_parameter;
+ pr "pub struct %sOptArgs%s {\n" cname opt_life_parameter;
List.iter (
fun optarg ->
let n = translate_bad_symbols (name_of_optargt optarg) in
match optarg with
| OBool _ ->
- pr " _%s: Option<bool>,\n" n
+ pr " pub %s: Option<bool>,\n" n
| OInt _ ->
- pr " _%s: Option<i32>,\n" n
+ pr " pub %s: Option<i32>,\n" n
| OInt64 _ ->
- pr " _%s: Option<i64>,\n" n
+ pr " pub %s: Option<i64>,\n" n
| OString _ ->
- pr " _%s: Option<&'a str>,\n" n
+ pr " pub %s: Option<&'a str>,\n" n
| OStringList _ ->
- pr " _%s: Option<Vec<&'a str>>,\n" n
+ pr " pub %s: Option<&'a [&'a str]>,\n"
n
) optargs;
pr "}\n\n";
+ pr "struct CExpr%sOptArgs {\n" cname;
+ List.iter (
+ fun optarg ->
+ let n = translate_bad_symbols (name_of_optargt optarg) in
+ match optarg with
+ | OBool _ | OInt _ ->
+ pr " %s: Option<c_int>,\n" n
+ | OInt64 _ ->
+ pr " %s: Option<i64>,\n" n
+ | OString _ ->
+ pr " %s: Option<ffi::CString>,\n" n
+ | OStringList _ ->
+ (* buffers and their pointer vector *)
+ pr " %s: Option<(Vec<ffi::CString>, Vec<*const
c_char>)>,\n" n
+ ) optargs;
+ pr "}\n\n";
+
+ pr "impl%s TryFrom<%sOptArgs%s> for CExpr%sOptArgs {\n"
+ opt_life_parameter cname opt_life_parameter cname;
+ pr " type Error = Error;\n";
+ pr " fn try_from(optargs: %sOptArgs%s) -> Result<Self,
Self::Error> {\n" cname opt_life_parameter;
+ pr " Ok(CExpr%sOptArgs {\n" cname;
+ List.iteri (
+ fun index optarg ->
+ let n = translate_bad_symbols (name_of_optargt optarg) in
+ match optarg with
+ | OBool _ ->
+ pr " %s: optargs.%s.map(|b| if b { 1 } else { 0 }),\n" n
n;
+ | OInt _ | OInt64 _ ->
+ pr " %s: optargs.%s, \n" n n;
+ | OString _ ->
+ pr " %s: optargs.%s.map(|v|
ffi::CString::new(v)).transpose()?,\n" n n;
+ | OStringList _ ->
+ pr " %s: optargs.%s.map(\n" n n;
+ pr " |v| Ok::<_, Error>({\n";
+ pr " let v = arg_string_list(v)?;\n";
+ pr " let mut w =
(&v).into_iter()\n";
+ pr " .map(|v|
v.as_ptr())\n";
+ pr "
.collect::<Vec<_>>();\n";
+ pr " w.push(ptr::null());\n";
+ pr " (v, w)\n";
+ pr " })\n";
+ pr " ).transpose()?,\n";
+ ) optargs;
+ pr " })\n";
+ pr " }\n";
+ pr "}\n";
+
(* raw struct for C bindings *)
pr "#[repr(C)]\n";
- pr "struct RawOptArgs%s {\n" cname;
+ pr "struct Raw%sOptArgs {\n" cname;
pr " bitmask: u64,\n";
List.iter (
fun optarg ->
@@ -422,41 +521,33 @@ impl UUID {
) optargs;
pr "}\n\n";
- pr "impl%s convert::From<OptArgs%s%s> for RawOptArgs%s {\n"
- opt_life_parameter cname opt_life_parameter cname;
- pr " fn from(optargs: OptArgs%s%s) -> Self {\n" cname
opt_life_parameter;
+ pr "impl convert::From<&CExpr%sOptArgs> for Raw%sOptArgs
{\n"
+ cname cname;
+ pr " fn from(optargs: &CExpr%sOptArgs) -> Self {\n" cname;
pr " let mut bitmask = 0;\n";
- pr " RawOptArgs%s {\n" cname;
+ pr " Raw%sOptArgs {\n" cname;
List.iteri (
fun index optarg ->
let n = translate_bad_symbols (name_of_optargt optarg) in
match optarg with
- | OBool _ ->
- pr " %s: if let Some(v) = optargs._%s {\n" n n;
- pr " bitmask |= 1 << %d;\n" index;
- pr " if v { 1 } else { 0 }\n";
- pr " } else {\n";
- pr " 0\n";
- pr " },\n";
- | OInt _ | OInt64 _ ->
- pr " %s: if let Some(v) = optargs._%s {\n" n n;
+ | OBool _ | OInt _ | OInt64 _ ->
+ pr " %s: if let Some(v) = optargs.%s {\n" n n;
pr " bitmask |= 1 << %d;\n" index;
pr " v\n";
pr " } else {\n";
pr " 0\n";
pr " },\n";
| OString _ ->
- pr " %s: if let Some(v) = optargs._%s {\n" n n;
+ pr " %s: if let Some(ref v) = optargs.%s {\n" n n;
pr " bitmask |= 1 << %d;\n" index;
- pr " let y: &str = &v;\n";
- pr " ffi::CString::new(y).unwrap().as_ptr()\n";
+ pr " v.as_ptr()\n";
pr " } else {\n";
pr " ptr::null()\n";
pr " },\n";
| OStringList _ ->
- pr " %s: if let Some(v) = optargs._%s {\n" n n;
+ pr " %s: if let Some((_, ref v)) = optargs.%s {\n" n n;
pr " bitmask |= 1 << %d;\n" index;
- pr " arg_string_list(&v).as_ptr()";
+ pr " v.as_ptr()\n";
pr " } else {\n";
pr " ptr::null()\n";
pr " },\n";
@@ -465,29 +556,6 @@ impl UUID {
pr " }\n";
pr " }\n";
pr "}\n";
-
- pr "impl%s OptArgs%s%s {\n" opt_life_parameter cname
opt_life_parameter;
- List.iter (
- fun optarg ->
- let n = translate_bad_symbols (name_of_optargt optarg) in
- pr " pub fn %s(self, %s: " n n;
- (match optarg with
- | OBool _ ->
- pr "bool"
- | OInt _ ->
- pr "i32"
- | OInt64 _ ->
- pr "i64"
- | OString _ ->
- pr "&'a str"
- | OStringList _ ->
- pr "Vec<&'a str>"
- );
- pr ") -> OptArgs%s%s {\n" cname opt_life_parameter;
- pr " OptArgs%s { _%s: Some(%s), ..self }\n" cname n n;
- pr " }\n"
- ) optargs;
- pr "}\n\n";
);
) (actions |> external_functions |> sort);
@@ -497,7 +565,8 @@ impl UUID {
fun ({ name = name; shortdesc = shortdesc;
style = (ret, args, optargs) } as f) ->
let cname = snake2caml name in
- pr "fn %s(g: *const guestfs_h" f.c_function;
+ pr " #[allow(non_snake_case)]\n";
+ pr " fn %s(g: *const guestfs_h" f.c_function;
List.iter (
fun arg ->
pr ", ";
@@ -516,7 +585,7 @@ impl UUID {
| _ -> ()
);
if optargs <> [] then
- pr ", optarg: *const RawOptArgs%s" cname;
+ pr ", optarg: *const Raw%sOptArgs" cname;
pr ") -> ";
@@ -541,14 +610,16 @@ impl UUID {
pr "impl Handle {\n";
List.iter (
- fun ({ name = name; shortdesc = shortdesc;
+ fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc;
style = (ret, args, optargs) } as f) ->
let cname = snake2caml name in
- pr " /// %s \n" shortdesc;
+ pr " /// %s\n" shortdesc;
+ pr " #[allow(non_snake_case)]\n";
pr " pub fn %s" name;
(* generate arguments *)
pr "(&self, ";
+
let comma = ref false in
List.iter (
fun arg ->
@@ -560,14 +631,14 @@ impl UUID {
| Int64 n -> pr "%s: i64" n
| String (_, n) -> pr "%s: &str" n
| OptString n -> pr "%s: Option<&str>" n
- | StringList (_, n) -> pr "%s: Vec<&str>" n
- | BufferIn n -> pr "%s: Vec<u8>" n
- | Pointer (_, n) -> pr "%s: usize" n
+ | StringList (_, n) -> pr "%s: &[&str]" n
+ | BufferIn n -> pr "%s: &[u8]" n
+ | Pointer (_, n) -> pr "%s: *mut c_void" n
) args;
if optargs <> [] then (
if !comma then pr ", ";
comma := true;
- pr "optargs: OptArgs%s" cname
+ pr "optargs: %sOptArgs" cname
);
pr ")";
@@ -592,45 +663,37 @@ impl UUID {
| RBufferOut _ -> pr "Vec<u8>");
pr ", Error> {\n";
+
let _pr = pr in
let pr fs = indent 2; pr fs in
List.iter (
function
| Bool n ->
- pr "let c_%s = if %s { 1 } else { 0 };\n" n n
+ pr "let %s = if %s { 1 } else { 0 };\n" n n
| String (_, n) ->
- (* TODO: handle errors *)
- pr "let c_%s = \n" n;
- pr " ffi::CString::new(%s).expect(\"CString::new
failed\").as_ptr();\n" n;
+ pr "let c_%s = ffi::CString::new(%s)?;\n" n n;
| OptString n ->
- pr "let c_%s = match %s {" n n;
- pr " Some(s) => \n";
- pr " ffi::CString::new(s)\n";
- pr " .expect(\"CString::new failed\")\n";
- pr " .as_ptr(),\n";
- pr " None => ptr::null(),\n";
- pr "};\n";
+ pr "let c_%s = %s.map(|s| ffi::CString::new(s)).transpose()?;\n" n
n;
| StringList (_, n) ->
- pr "let c_%s = arg_string_list(&%s).as_ptr();\n" n n;
+ pr "let c_%s_v = arg_string_list(%s)?;\n" n n;
+ pr "let mut c_%s = (&c_%s_v).into_iter().map(|v|
v.as_ptr()).collect::<Vec<_>>();\n" n n;
+ pr "c_%s.push(ptr::null());\n" n;
| BufferIn n ->
- pr "let c_%s_len = (&%s).len();\n" n n;
- pr "let c_%s = ffi::CString::new(%s)\n" n n;
- pr " .expect(\"CString::new failed\")\n";
- pr " .as_ptr();\n";
+ pr "let c_%s_len = %s.len();\n" n n;
+ pr "let c_%s = unsafe {
ffi::CString::from_vec_unchecked(%s.to_vec())};\n" n n;
| Int _ | Int64 _ | Pointer _ -> ()
) args;
- (* TODO: handle optargs *)
- if optargs <> [] then (
- pr "let optargs_raw = RawOptArgs%s::from(optargs);\n" cname;
- );
-
(match ret with
| RBufferOut _ ->
pr "let mut size = 0usize;\n"
| _ -> ()
);
+ if optargs <> [] then (
+ pr "let optargs_cexpr = CExpr%sOptArgs::try_from(optargs)?;\n" cname;
+ );
+
pr "\n";
pr "let r = unsafe { %s(self.g" f.c_function;
@@ -639,18 +702,19 @@ impl UUID {
fun arg ->
pr ", ";
match arg with
- | Bool n | String (_, n) | OptString n -> pr "c_%s" n
- | Int n | Int64 n -> pr "%s" n
- | Pointer _ -> pr "ptr::null()" (* XXX: what is pointer? *)
- | StringList (_, n) -> pr "c_%s as *const *const c_char" n
- | BufferIn n -> pr "c_%s, c_%s_len" n n
+ | String (_, n) -> pr "(&c_%s).as_ptr()" n
+ | OptString n -> pr "match &c_%s { Some(ref s) => s.as_ptr(),
None => ptr::null() }\n" n
+ | StringList (_, n) -> pr "(&c_%s).as_ptr() as *const *const
c_char" n
+ | Bool n | Int n | Int64 n | Pointer (_, n) -> pr "%s" n
+ | BufferIn n -> pr "(&c_%s).as_ptr(), c_%s_len" n n
) args;
(match ret with
- | RBufferOut _ -> pr ", &size as *const usize"
+ | RBufferOut _ -> pr ", &mut size as *mut usize"
| _ -> ()
);
if optargs <> [] then (
- pr ", &optargs_raw as *const RawOptArgs%s" cname;
+ pr ", &(Raw%sOptArgs::from(&optargs_cexpr)) as *const
Raw%sOptArgs"
+ cname cname;
);
pr ") };\n";
@@ -660,66 +724,85 @@ impl UUID {
| `CannotReturnError -> ()
| `ErrorIsMinusOne ->
pr "if r == -1 {\n";
- pr " return Err(self.get_error_from_handle (\"%s\"));\n"
name;
+ pr " return Err(self.get_error_from_handle(\"%s\"));\n"
name;
pr "}\n"
| `ErrorIsNULL ->
pr "if r.is_null() {\n";
- pr " return Err(self.get_error_from_handle (\"%s\"));\n"
name;
+ pr " return Err(self.get_error_from_handle(\"%s\"));\n"
name;
pr "}\n"
);
+
+ (* This part is not required, but type system will guarantee that
+ * the buffers are still alive. This is useful because Rust cannot
+ * know whether raw pointers used above are alive or not.
+ *)
+ List.iter (
+ function
+ | Bool _ | Int _ | Int64 _ | Pointer _ -> ()
+ | String (_, n)
+ | OptString n
+ | BufferIn n -> pr "drop(c_%s);\n" n;
+ | StringList (_, n) ->
+ pr "drop(c_%s);\n" n;
+ pr "drop(c_%s_v);\n" n;
+ ) args;
+ if optargs <> [] then (
+ pr "drop(optargs_cexpr);\n";
+ );
+
pr "Ok(";
let pr = _pr in
+ let pr3 fs = indent 3; pr fs in
(match ret with
| RErr -> pr "()"
| RInt _ | RInt64 _ -> pr "r"
| RBool _ -> pr "r != 0"
| RConstString _ ->
- pr "unsafe{ ffi::CStr::from_ptr(r) }.to_str().unwrap()\n"
+ pr "unsafe{ ffi::CStr::from_ptr(r) }.to_str()?"
| RString _ ->
- pr "{";
- pr " let s = unsafe {ffi::CStr::from_ptr(r)}\n";
- pr " .to_str().unwrap().to_string();\n";
- pr " unsafe { free(r as * const c_void) };\n";
- pr " s\n";
- pr "}\n";
+ pr "{\n";
+ pr3 "let s = unsafe { ffi::CStr::from_ptr(r) };\n";
+ pr3 "unsafe { free(r as *const c_void) };\n";
+ pr3 "s.to_str()?.to_string()\n";
+ indent 2; pr "}";
| RConstOptString _ ->
- indent 3; pr "if r.is_null() {\n";
- indent 3; pr " None\n";
- indent 3; pr "} else {\n";
- indent 3; pr " Some(unsafe { ffi::CStr::from_ptr(r)
}.to_str().unwrap())\n";
- indent 3; pr "}";
+ pr "if r.is_null() {\n";
+ pr3 "None\n";
+ indent 2; pr "} else {\n";
+ pr3 "Some(unsafe { ffi::CStr::from_ptr(r) }.to_str()?)\n";
+ indent 2; pr "}";
| RStringList _ ->
pr "{\n";
- pr " let s = string_list(r);\n";
- pr " free_string_list(r);\n";
- pr " s\n";
- pr "}\n";
+ pr3 "let s = string_list(r);\n";
+ pr3 "free_string_list(r);\n";
+ pr3 "s?\n";
+ indent 2; pr "}";
| RStruct (_, n) ->
let sn = camel_name_of_struct n in
pr "{\n";
- pr " let s = %s::from(r);\n" sn;
- pr " unsafe { guestfs_free_%s(r) };\n" n;
- pr " s\n";
- pr "}\n";
+ pr3 "let s = %s::try_from(r);\n" sn;
+ pr3 "unsafe { guestfs_free_%s(r) };\n" n;
+ pr3 "s?\n";
+ indent 2; pr "}";
| RStructList (_, n) ->
let sn = camel_name_of_struct n in
pr "{\n";
- pr " let l = struct_list::<Raw%s, %s>(r);\n" sn sn;
- pr " unsafe { guestfs_free_%s_list(r) };" n;
- pr " l\n";
- pr "}\n";
+ pr3 "let l = struct_list::<Raw%s, %s>(r);\n" sn sn;
+ pr3 "unsafe { guestfs_free_%s_list(r) };\n" n;
+ pr3 "l?\n";
+ indent 2; pr "}";
| RHashtable _ ->
pr "{\n";
- pr " let h = hashmap(r);\n";
- pr " free_string_list(r);\n";
- pr " h\n";
- pr "}\n";
+ pr3 "let h = hashmap(r);\n";
+ pr3 "free_string_list(r);\n";
+ pr3 "h?\n";
+ indent 2; pr "}";
| RBufferOut _ ->
pr "{\n";
- pr " let s = unsafe { slice::from_raw_parts(r, size)
}.to_vec();\n";
- pr " unsafe { free(r as * const c_void) } ;\n";
- pr " s\n";
- pr "}\n";
+ pr3 "let s = unsafe { slice::from_raw_parts(r, size) }.to_vec();\n";
+ pr3 "unsafe { free(r as *const c_void) } ;\n";
+ pr3 "s\n";
+ indent 2; pr "}";
);
pr ")\n";
pr " }\n\n"
diff --git a/generator/rust.mli b/generator/rust.mli
index 4fef55d4e..5410286c8 100644
--- a/generator/rust.mli
+++ b/generator/rust.mli
@@ -16,4 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
-val generate_rust: unit -> unit
\ No newline at end of file
+val generate_rust: unit -> unit
+
+(* for bindtests.ml *)
+val snake2caml: string -> string
diff --git a/rust/.gitignore b/rust/.gitignore
new file mode 100644
index 000000000..53eaa2196
--- /dev/null
+++ b/rust/.gitignore
@@ -0,0 +1,2 @@
+/target
+**/*.rs.bk
diff --git a/rust/Makefile.am b/rust/Makefile.am
index e8bf27894..261cf4a5c 100644
--- a/rust/Makefile.am
+++ b/rust/Makefile.am
@@ -18,12 +18,26 @@
include $(top_srcdir)/subdir-rules.mk
generator_built = \
+ src/bin/bindtests.rs \
src/lib.rs
EXTRA_DIST = \
- $(generator_built)
+ .gitignore \
+ $(generator_built) \
+ tests/*.rs \
+ Cargo.toml \
+ Cargo.lock \
+ run-bindtests \
+ run-tests
if HAVE_RUST
+all: src/lib.rs
+ $(top_builddir)/run $(CARGO) build --release
+
+TESTS = run-bindtests run-tests
+
+CLEANFILES += target/*~
+
endif
diff --git a/rust/run-bindtests b/rust/run-bindtests
new file mode 100755
index 000000000..2986e898d
--- /dev/null
+++ b/rust/run-bindtests
@@ -0,0 +1,23 @@
+#!/bin/sh -
+# libguestfs Golang bindings
+# Copyright (C) 2013 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+set -e
+
+$CARGO run --bin bindtests > bindtests.tmp
+diff -u $srcdir/../bindtests bindtests.tmp
+rm bindtests.tmp
diff --git a/rust/run-tests b/rust/run-tests
new file mode 100755
index 000000000..694ecc9dd
--- /dev/null
+++ b/rust/run-tests
@@ -0,0 +1,21 @@
+#!/bin/sh -
+# libguestfs Golang tests
+# Copyright (C) 2013 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+set -e
+
+$CARGO test
diff --git a/rust/src/bin/.gitkeep b/rust/src/bin/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/rust/tests/010_load.rs b/rust/tests/010_load.rs
index eadd78896..4cb43f2c1 100644
--- a/rust/tests/010_load.rs
+++ b/rust/tests/010_load.rs
@@ -1,20 +1,20 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
diff --git a/rust/tests/020_create.rs b/rust/tests/020_create.rs
index 0b57b19d7..017dbbac0 100644
--- a/rust/tests/020_create.rs
+++ b/rust/tests/020_create.rs
@@ -1,20 +1,20 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
diff --git a/rust/tests/030_create_flags.rs b/rust/tests/030_create_flags.rs
index 5de0589c1..df3190d4c 100644
--- a/rust/tests/030_create_flags.rs
+++ b/rust/tests/030_create_flags.rs
@@ -1,19 +1,19 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
@@ -23,8 +23,7 @@ use guestfs::*;
fn create_flags() {
let _h = Handle::create_flags(CreateFlags::none()).expect("create_flags
fail");
// TODO: Add parse_environment to check the flag is created correctly
- let flags = CreateFlags::new()
- .create_no_environment(true);
+ let flags = CreateFlags::new().create_no_environment(true);
let _h = Handle::create_flags(flags).expect("create_flags fail");
// TODO: Add parse_environment to check the flag is created correctly
}
diff --git a/rust/tests/040_create_multiple.rs b/rust/tests/040_create_multiple.rs
index ee481c278..372fad7ee 100644
--- a/rust/tests/040_create_multiple.rs
+++ b/rust/tests/040_create_multiple.rs
@@ -1,20 +1,20 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
diff --git a/rust/tests/050_handle_properties.rs b/rust/tests/050_handle_properties.rs
index 3c7b449f9..0b955d5cf 100644
--- a/rust/tests/050_handle_properties.rs
+++ b/rust/tests/050_handle_properties.rs
@@ -1,20 +1,20 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
@@ -57,5 +57,6 @@ fn path() {
#[test]
fn add_drive() {
let g = guestfs::Handle::create().expect("create");
- g.add_drive("/dev/null",
Default::default()).expect("add_drive");
+ g.add_drive("/dev/null", Default::default())
+ .expect("add_drive");
}
diff --git a/rust/tests/070_opt_args.rs b/rust/tests/070_opt_args.rs
index 241c95b35..04b4890c2 100644
--- a/rust/tests/070_opt_args.rs
+++ b/rust/tests/070_opt_args.rs
@@ -1,20 +1,20 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
@@ -30,7 +30,12 @@ fn no_optargs() {
#[test]
fn one_optarg() {
let g = guestfs::Handle::create().expect("create");
- g.add_drive("/dev/null",
- guestfs::OptArgsAddDrive::default().readonly(true))
- .expect("add_drive");
+ g.add_drive(
+ "/dev/null",
+ guestfs::AddDriveOptArgs {
+ readonly: Some(true),
+ ..Default::default()
+ },
+ )
+ .expect("add_drive");
}
diff --git a/rust/tests/080_version.rs b/rust/tests/080_version.rs
index ab5314edc..19e441d67 100644
--- a/rust/tests/080_version.rs
+++ b/rust/tests/080_version.rs
@@ -1,29 +1,26 @@
-/* libguestfs Python bindings
- Copyright (C) 2009-2019 Red Hat Inc.
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
extern crate guestfs;
-use std::default::Default;
-
#[test]
fn version() {
let g = guestfs::Handle::create().expect("create");
let v = g.version().expect("version");
assert_eq!(v.major, 1)
}
-
diff --git a/rust/tests/090_ret_values.rs b/rust/tests/090_ret_values.rs
new file mode 100644
index 000000000..d3e2e80da
--- /dev/null
+++ b/rust/tests/090_ret_values.rs
@@ -0,0 +1,61 @@
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+extern crate guestfs;
+
+#[test]
+fn rint() {
+ let g = guestfs::Handle::create().expect("create");
+ assert_eq!(g.internal_test_rint("10").unwrap(), 10);
+ assert!(g.internal_test_rinterr().is_err())
+}
+
+#[test]
+fn rint64() {
+ let g = guestfs::Handle::create().expect("create");
+ assert_eq!(g.internal_test_rint64("10").unwrap(), 10);
+ assert!(g.internal_test_rint64err().is_err())
+}
+
+#[test]
+fn rbool() {
+ let g = guestfs::Handle::create().expect("create");
+ assert!(g.internal_test_rbool("true").unwrap());
+ assert!(!g.internal_test_rbool("false").unwrap());
+ assert!(g.internal_test_rboolerr().is_err())
+}
+
+#[test]
+fn rconststring() {
+ let g = guestfs::Handle::create().expect("create");
+ assert_eq!(
+ g.internal_test_rconststring("test").unwrap(),
+ "static string"
+ );
+ assert!(g.internal_test_rconststringerr().is_err())
+}
+
+#[test]
+fn rconstoptstring() {
+ let g = guestfs::Handle::create().expect("create");
+ assert_eq!(
+ g.internal_test_rconstoptstring("test").unwrap(),
+ Some("static string")
+ );
+ assert_eq!(g.internal_test_rconstoptstringerr().unwrap(), None)
+}
diff --git a/rust/tests/100_launch.rs b/rust/tests/100_launch.rs
new file mode 100644
index 000000000..1c1d8146a
--- /dev/null
+++ b/rust/tests/100_launch.rs
@@ -0,0 +1,65 @@
+/* libguestfs Rust bindings
+Copyright (C) 2009-2019 Red Hat Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+extern crate guestfs;
+
+use std::default::Default;
+
+#[test]
+fn launch() {
+ let g = guestfs::Handle::create().expect("create");
+ g.add_drive_scratch(500 * 1024 * 1024, Default::default())
+ .expect("add_drive_scratch");
+ g.launch().expect("launch");
+ g.pvcreate("/dev/sda").expect("pvcreate");
+ g.vgcreate("VG",
&["/dev/sda"]).expect("vgcreate");
+ g.lvcreate("LV1", "VG", 200).expect("lvcreate");
+ g.lvcreate("LV2", "VG", 200).expect("lvcreate");
+
+ let lvs = g.lvs().expect("lvs");
+ assert_eq!(
+ lvs,
+ vec!["/dev/VG/LV1".to_string(), "/dev/VG/LV2".to_string()]
+ );
+
+ g.mkfs("ext2", "/dev/VG/LV1", Default::default())
+ .expect("mkfs");
+ g.mount("/dev/VG/LV1", "/").expect("mount");
+ g.mkdir("/p").expect("mkdir");
+ g.touch("/q").expect("touch");
+
+ let mut dirs = g.readdir("/").expect("readdir");
+
+ dirs.sort_by(|a, b| a.name.cmp(&b.name));
+
+ let mut v = Vec::new();
+ for x in &dirs {
+ v.push((x.name.as_str(), x.ftyp as u8));
+ }
+ assert_eq!(
+ v,
+ vec![
+ (".", b'd'),
+ ("..", b'd'),
+ ("lost+found", b'd'),
+ ("p", b'd'),
+ ("q", b'r')
+ ]
+ );
+ g.shutdown().expect("shutdown");
+}
--
2.20.1 (Apple Git-117)