mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Rust bindings: Add Rust bindings
This patch includes Actions and their tests. Missing: - Events - Examples Rust bindings: Add create / close functions Rust bindings: Add 4 bindings tests Rust bindings: Add generator of structs Rust bindings: Add generator of structs for optional arguments Rust bindings: Add generator of function signatures Rust bindings: Complete actions Rust bindings: Fix memory management Rust bindings: Add bindtests Rust bindings: Add additional 4 bindings tests Rust bindings: Format test files Rust bindings: Incorporate bindings to build system
This commit is contained in:
committed by
Richard W.M. Jones
parent
6d251e3828
commit
3bbd00c83e
@@ -151,6 +151,9 @@ endif
|
||||
if HAVE_GOLANG
|
||||
SUBDIRS += golang golang/examples
|
||||
endif
|
||||
if HAVE_RUST
|
||||
SUBDIRS += rust
|
||||
endif
|
||||
|
||||
# Unconditional because nothing is built yet.
|
||||
SUBDIRS += csharp
|
||||
|
||||
@@ -161,6 +161,8 @@ HEADING([Checking for Go])
|
||||
m4_include([m4/guestfs-golang.m4])
|
||||
HEADING([Checking for GObject Introspection])
|
||||
m4_include([m4/guestfs-gobject.m4])
|
||||
HEADING([Checking for Rust])
|
||||
m4_include([m4/guestfs-rust.m4])
|
||||
HEADING([Checking for Vala])
|
||||
VAPIGEN_CHECK
|
||||
|
||||
@@ -315,6 +317,8 @@ AC_CONFIG_FILES([Makefile
|
||||
ruby/Rakefile
|
||||
ruby/examples/Makefile
|
||||
ruby/ext/guestfs/extconf.rb
|
||||
rust/Makefile
|
||||
rust/Cargo.toml
|
||||
sparsify/Makefile
|
||||
sysprep/Makefile
|
||||
test-data/Makefile
|
||||
@@ -433,6 +437,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."
|
||||
|
||||
@@ -103,6 +103,8 @@ sources = \
|
||||
python.mli \
|
||||
ruby.ml \
|
||||
ruby.mli \
|
||||
rust.ml \
|
||||
rust.mli \
|
||||
structs.ml \
|
||||
structs.mli \
|
||||
tests_c_api.ml \
|
||||
@@ -161,6 +163,7 @@ objects = \
|
||||
lua.cmo \
|
||||
GObject.cmo \
|
||||
golang.cmo \
|
||||
rust.cmo \
|
||||
bindtests.cmo \
|
||||
errnostring.cmo \
|
||||
customize.cmo \
|
||||
|
||||
@@ -983,6 +983,73 @@ and generate_php_bindtests () =
|
||||
|
||||
dump "bindtests"
|
||||
|
||||
and generate_rust_bindtests () =
|
||||
let copywrites = ["Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>"] in
|
||||
generate_header ~copywrites:copywrites 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.
|
||||
*)
|
||||
|
||||
@@ -28,3 +28,4 @@ val generate_perl_bindtests : unit -> unit
|
||||
val generate_php_bindtests : unit -> unit
|
||||
val generate_python_bindtests : unit -> unit
|
||||
val generate_ruby_bindtests : unit -> unit
|
||||
val generate_rust_bindtests : unit -> unit
|
||||
|
||||
@@ -76,7 +76,7 @@ type comment_style =
|
||||
| ErlangStyle | LuaStyle | PODStyle
|
||||
type license = GPLv2plus | LGPLv2plus
|
||||
|
||||
let generate_header ?(inputs = []) ?emacs_mode comment license =
|
||||
let generate_header ?(copywrites = ["Red Hat Inc."]) ?(inputs = []) ?emacs_mode comment license =
|
||||
let c = match comment with
|
||||
| CStyle -> pr "/* "; " *"
|
||||
| CPlusPlusStyle -> pr "// "; "//"
|
||||
@@ -102,7 +102,9 @@ let generate_header ?(inputs = []) ?emacs_mode comment license =
|
||||
);
|
||||
pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
|
||||
pr "%s\n" c;
|
||||
pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
|
||||
List.iter (fun x ->
|
||||
pr "%s Copyright (C) %s %s\n" c copyright_years x;
|
||||
) copywrites;
|
||||
pr "%s\n" c;
|
||||
(match license with
|
||||
| GPLv2plus ->
|
||||
|
||||
@@ -31,4 +31,4 @@ val version_added : Types.action -> string option
|
||||
|
||||
val copyright_years : string
|
||||
|
||||
val generate_header : ?inputs:string list -> ?emacs_mode:string -> comment_style -> license -> unit
|
||||
val generate_header : ?copywrites:string list -> ?inputs:string list -> ?emacs_mode:string -> comment_style -> license -> unit
|
||||
|
||||
@@ -363,6 +363,11 @@ Run it from the top source directory using the command
|
||||
output_to "customize/customize-options.pod"
|
||||
Customize.generate_customize_options_pod;
|
||||
|
||||
output_to "rust/src/guestfs.rs"
|
||||
Rust.generate_rust;
|
||||
output_to "rust/src/bin/bindtests.rs"
|
||||
Bindtests.generate_rust_bindtests;
|
||||
|
||||
(* Generate the list of files generated -- last. *)
|
||||
printf "generated %d lines of code\n" (get_lines_generated ());
|
||||
let files = List.sort compare (get_files_generated ()) in
|
||||
|
||||
558
generator/rust.ml
Normal file
558
generator/rust.ml
Normal file
@@ -0,0 +1,558 @@
|
||||
(* libguestfs
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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
|
||||
*)
|
||||
|
||||
(* Please read generator/README first. *)
|
||||
|
||||
open Std_utils
|
||||
open Types
|
||||
open Utils
|
||||
open Pr
|
||||
open Docstrings
|
||||
open Optgroups
|
||||
open Actions
|
||||
open Structs
|
||||
open C
|
||||
open Events
|
||||
|
||||
let copywrites = ["Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>"]
|
||||
|
||||
(* Utilities for Rust *)
|
||||
(* Are there corresponding functions to them? *)
|
||||
(* Should they be placed in utils.ml? *)
|
||||
let rec indent = function
|
||||
| x when x > 0 -> pr " "; indent (x - 1)
|
||||
| _ -> ()
|
||||
|
||||
let snake2caml name =
|
||||
let l = String.nsplit "_" name in
|
||||
let l = List.map String.capitalize_ascii l in
|
||||
String.concat "" l
|
||||
|
||||
(* because there is a function which contains 'unsafe' field *)
|
||||
let black_list = ["unsafe"]
|
||||
|
||||
let translate_bad_symbols s =
|
||||
if List.mem s black_list then
|
||||
s ^ "_"
|
||||
else
|
||||
s
|
||||
|
||||
let generate_rust () =
|
||||
generate_header ~copywrites:copywrites CStyle LGPLv2plus;
|
||||
|
||||
pr "
|
||||
use crate::base::*;
|
||||
use crate::utils::*;
|
||||
use crate::error::*;
|
||||
use std::collections;
|
||||
use std::convert;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
extern \"C\" {
|
||||
fn free(buf: *const c_void);
|
||||
}
|
||||
";
|
||||
|
||||
List.iter (
|
||||
fun { s_camel_name = name; s_name = c_name; s_cols = cols } ->
|
||||
pr "\n";
|
||||
pr "pub struct %s {\n" name;
|
||||
List.iter (
|
||||
function
|
||||
| n, FChar -> pr " pub %s: i8,\n" n
|
||||
| n, FString -> pr " pub %s: String,\n" n
|
||||
| n, FBuffer -> pr " pub %s: Vec<u8>,\n" n
|
||||
| n, FUInt32 -> pr " pub %s: u32,\n" n
|
||||
| n, FInt32 -> pr " pub %s: i32,\n" n
|
||||
| n, (FUInt64 | FBytes) -> pr " pub %s: u64,\n" n
|
||||
| n, FInt64 -> pr " pub %s: i64,\n" n
|
||||
| n, FUUID -> pr " pub %s: UUID,\n" n
|
||||
| n, FOptPercent -> pr " pub %s: Option<f32>,\n" n
|
||||
) cols;
|
||||
pr "}\n";
|
||||
pr "#[repr(C)]\n";
|
||||
pr "struct Raw%s {\n" name;
|
||||
List.iter (
|
||||
function
|
||||
| n, FChar -> pr " %s: c_char,\n" n
|
||||
| n, FString -> pr " %s: *const c_char,\n" n
|
||||
| n, FBuffer ->
|
||||
pr " %s_len: usize,\n" n;
|
||||
pr " %s: *const c_char,\n" n;
|
||||
| n, FUUID -> pr " %s: [u8; 32],\n" n
|
||||
| n, FUInt32 -> pr " %s: u32,\n" n
|
||||
| n, FInt32 -> pr " %s: i32,\n" n
|
||||
| n, (FUInt64 | FBytes) -> pr " %s: u64,\n" n
|
||||
| n, FInt64 -> pr " %s: i64,\n" n
|
||||
| n, FOptPercent -> pr " %s: f32,\n" n
|
||||
) cols;
|
||||
pr "}\n";
|
||||
pr "\n";
|
||||
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 4;
|
||||
match x with
|
||||
| n, FChar ->
|
||||
pr "%s: (*raw).%s as i8,\n" n n;
|
||||
| n, FString ->
|
||||
pr "%s: char_ptr_to_string((*raw).%s)?,\n" n n;
|
||||
| n, FBuffer ->
|
||||
pr "%s: slice::from_raw_parts((*raw).%s as *const u8, (*raw).%s_len).to_vec(),\n" n n n
|
||||
| n, FUUID ->
|
||||
pr "%s: UUID::new((*raw).%s),\n" n n
|
||||
| n, (FUInt32 | FInt32 | FUInt64 | FInt64 | FBytes) ->
|
||||
pr "%s: (*raw).%s,\n" n n
|
||||
| n, FOptPercent ->
|
||||
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"
|
||||
) external_structs;
|
||||
|
||||
(* generate free functionf of structs *)
|
||||
pr "\n";
|
||||
pr "extern \"C\" {\n";
|
||||
List.iter (
|
||||
fun { s_camel_name = name; s_name = c_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 (
|
||||
fun ({ name = name; shortdesc = shortdesc;
|
||||
style = (ret, args, optargs) }) ->
|
||||
let cname = snake2caml name in
|
||||
let contains_ptr =
|
||||
List.exists (
|
||||
function
|
||||
| OString _
|
||||
| OStringList _ -> true
|
||||
| _ -> false
|
||||
)
|
||||
in
|
||||
let opt_life_parameter = if contains_ptr optargs then "<'a>" else "" in
|
||||
if optargs <> [] then (
|
||||
pr "\n";
|
||||
pr "/* Optional Structs */\n";
|
||||
pr "#[derive(Default)]\n";
|
||||
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 " pub %s: Option<bool>,\n" n
|
||||
| OInt _ ->
|
||||
pr " pub %s: Option<i32>,\n" n
|
||||
| OInt64 _ ->
|
||||
pr " pub %s: Option<i64>,\n" n
|
||||
| OString _ ->
|
||||
pr " pub %s: Option<&'a str>,\n" n
|
||||
| OStringList _ ->
|
||||
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 Raw%sOptArgs {\n" cname;
|
||||
pr " bitmask: u64,\n";
|
||||
List.iter (
|
||||
fun optarg ->
|
||||
let n = translate_bad_symbols (name_of_optargt optarg) in
|
||||
match optarg with
|
||||
| OBool _ ->
|
||||
pr " %s: c_int,\n" n
|
||||
| OInt _ ->
|
||||
pr " %s: c_int,\n" n
|
||||
| OInt64 _ ->
|
||||
pr " %s: i64,\n" n
|
||||
| OString _ ->
|
||||
pr " %s: *const c_char,\n" n
|
||||
| OStringList _ ->
|
||||
pr " %s: *const *const c_char,\n" n
|
||||
) optargs;
|
||||
pr "}\n\n";
|
||||
|
||||
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 " Raw%sOptArgs {\n" cname;
|
||||
List.iteri (
|
||||
fun index optarg ->
|
||||
let n = translate_bad_symbols (name_of_optargt optarg) in
|
||||
match optarg with
|
||||
| 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(ref v) = optargs.%s {\n" n n;
|
||||
pr " bitmask |= 1 << %d;\n" index;
|
||||
pr " v.as_ptr()\n";
|
||||
pr " } else {\n";
|
||||
pr " ptr::null()\n";
|
||||
pr " },\n";
|
||||
| OStringList _ ->
|
||||
pr " %s: if let Some((_, ref v)) = optargs.%s {\n" n n;
|
||||
pr " bitmask |= 1 << %d;\n" index;
|
||||
pr " v.as_ptr()\n";
|
||||
pr " } else {\n";
|
||||
pr " ptr::null()\n";
|
||||
pr " },\n";
|
||||
) optargs;
|
||||
pr " bitmask,\n";
|
||||
pr " }\n";
|
||||
pr " }\n";
|
||||
pr "}\n";
|
||||
);
|
||||
) (actions |> external_functions |> sort);
|
||||
|
||||
(* extern C APIs *)
|
||||
pr "extern \"C\" {\n";
|
||||
List.iter (
|
||||
fun ({ name = name; shortdesc = shortdesc;
|
||||
style = (ret, args, optargs) } as f) ->
|
||||
let cname = snake2caml name in
|
||||
pr " #[allow(non_snake_case)]\n";
|
||||
pr " fn %s(g: *const guestfs_h" f.c_function;
|
||||
List.iter (
|
||||
fun arg ->
|
||||
pr ", ";
|
||||
match arg with
|
||||
| Bool n -> pr "%s: c_int" n
|
||||
| String (_, n) -> pr "%s: *const c_char" n
|
||||
| OptString n -> pr "%s: *const c_char" n
|
||||
| Int n -> pr "%s: c_int" n
|
||||
| Int64 n -> pr "%s: i64" n
|
||||
| Pointer (_, n) -> pr "%s: *const ffi::c_void" n
|
||||
| StringList (_, n) -> pr "%s: *const *const c_char" n
|
||||
| BufferIn n -> pr "%s: *const c_char, %s_len: usize" n n
|
||||
) args;
|
||||
(match ret with
|
||||
| RBufferOut _ -> pr ", size: *const usize"
|
||||
| _ -> ()
|
||||
);
|
||||
if optargs <> [] then
|
||||
pr ", optarg: *const Raw%sOptArgs" cname;
|
||||
|
||||
pr ") -> ";
|
||||
|
||||
(match ret with
|
||||
| RErr | RInt _ | RBool _ -> pr "c_int"
|
||||
| RInt64 _ -> pr "i64"
|
||||
| RConstString _ | RString _ | RConstOptString _ -> pr "*const c_char"
|
||||
| RBufferOut _ -> pr "*const u8"
|
||||
| RStringList _ | RHashtable _-> pr "*const *const c_char"
|
||||
| RStruct (_, n) ->
|
||||
let n = camel_name_of_struct n in
|
||||
pr "*const Raw%s" n
|
||||
| RStructList (_, n) ->
|
||||
let n = camel_name_of_struct n in
|
||||
pr "*const RawList<Raw%s>" n
|
||||
);
|
||||
pr ";\n";
|
||||
|
||||
) (actions |> external_functions |> sort);
|
||||
pr "}\n";
|
||||
|
||||
|
||||
pr "impl Handle {\n";
|
||||
List.iter (
|
||||
fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc;
|
||||
style = (ret, args, optargs) } as f) ->
|
||||
let cname = snake2caml name in
|
||||
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 ->
|
||||
if !comma then pr ", ";
|
||||
comma := true;
|
||||
match arg with
|
||||
| Bool n -> pr "%s: bool" n
|
||||
| Int n -> pr "%s: i32" n
|
||||
| Int64 n -> pr "%s: i64" n
|
||||
| String (_, n) -> pr "%s: &str" n
|
||||
| OptString n -> pr "%s: Option<&str>" 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: %sOptArgs" cname
|
||||
);
|
||||
pr ")";
|
||||
|
||||
(* generate return type *)
|
||||
pr " -> Result<";
|
||||
(match ret with
|
||||
| RErr -> pr "()"
|
||||
| RInt _ -> pr "i32"
|
||||
| RInt64 _ -> pr "i64"
|
||||
| RBool _ -> pr "bool"
|
||||
| RConstString _ -> pr "&'static str"
|
||||
| RString _ -> pr "String"
|
||||
| RConstOptString _ -> pr "Option<&'static str>"
|
||||
| RStringList _ -> pr "Vec<String>"
|
||||
| RStruct (_, sn) ->
|
||||
let sn = camel_name_of_struct sn in
|
||||
pr "%s" sn
|
||||
| RStructList (_, sn) ->
|
||||
let sn = camel_name_of_struct sn in
|
||||
pr "Vec<%s>" sn
|
||||
| RHashtable _ -> pr "collections::HashMap<String, String>"
|
||||
| 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 %s = if %s { 1 } else { 0 };\n" n n
|
||||
| String (_, n) ->
|
||||
pr "let c_%s = ffi::CString::new(%s)?;\n" n n;
|
||||
| OptString n ->
|
||||
pr "let c_%s = %s.map(|s| ffi::CString::new(s)).transpose()?;\n" n n;
|
||||
| StringList (_, 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 = unsafe { ffi::CString::from_vec_unchecked(%s.to_vec())};\n" n n;
|
||||
| Int _ | Int64 _ | Pointer _ -> ()
|
||||
) args;
|
||||
|
||||
(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;
|
||||
let pr = _pr in
|
||||
List.iter (
|
||||
fun arg ->
|
||||
pr ", ";
|
||||
match arg with
|
||||
| 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 ", &mut size as *mut usize"
|
||||
| _ -> ()
|
||||
);
|
||||
if optargs <> [] then (
|
||||
pr ", &(Raw%sOptArgs::from(&optargs_cexpr)) as *const Raw%sOptArgs"
|
||||
cname cname;
|
||||
);
|
||||
pr ") };\n";
|
||||
|
||||
let _pr = pr in
|
||||
let pr fs = indent 2; pr fs in
|
||||
(match errcode_of_ret ret with
|
||||
| `CannotReturnError -> ()
|
||||
| `ErrorIsMinusOne ->
|
||||
pr "if r == -1 {\n";
|
||||
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 "}\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()?"
|
||||
| RString _ ->
|
||||
pr "{\n";
|
||||
pr3 "let s = unsafe { char_ptr_to_string(r) };\n";
|
||||
pr3 "unsafe { free(r as *const c_void) };";
|
||||
pr3 "s?\n";
|
||||
indent 2; pr "}";
|
||||
| RConstOptString _ ->
|
||||
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";
|
||||
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";
|
||||
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";
|
||||
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";
|
||||
pr3 "let h = hashmap(r);\n";
|
||||
pr3 "free_string_list(r);\n";
|
||||
pr3 "h?\n";
|
||||
indent 2; pr "}";
|
||||
| RBufferOut _ ->
|
||||
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"
|
||||
) (actions |> external_functions |> sort);
|
||||
pr "}\n"
|
||||
22
generator/rust.mli
Normal file
22
generator/rust.mli
Normal file
@@ -0,0 +1,22 @@
|
||||
(* libguestfs
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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
|
||||
*)
|
||||
|
||||
val generate_rust: unit -> unit
|
||||
|
||||
(* for bindtests.ml *)
|
||||
val snake2caml: string -> string
|
||||
33
m4/guestfs-rust.m4
Normal file
33
m4/guestfs-rust.m4
Normal file
@@ -0,0 +1,33 @@
|
||||
# libguestfs
|
||||
# Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
dnl Rust
|
||||
AC_ARG_ENABLE([rust],
|
||||
AS_HELP_STRING([--disable-rust], [disable Rust language bindings]),
|
||||
[],
|
||||
[enable_rust=yes])
|
||||
AS_IF([test "x$enable_rust" != "xno"],[
|
||||
AC_CHECK_PROG([RUSTC],[rustc],[rustc],[no])
|
||||
AC_CHECK_PROG([CARGO],[cargo],[cargo],[no])
|
||||
|
||||
AS_IF([test "x$RUSTC" == "xno"], [AC_MSG_WARN([rustc not found])])
|
||||
AS_IF([test "x$CARGO" == "xno"], [AC_MSG_WARN([cargo not found])])
|
||||
],[
|
||||
RUSTC=no
|
||||
CARGO=no
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_RUST],[test "x$RUSTC" != "xno" && test "x$CARGO" != "xno"])
|
||||
10
run.in
10
run.in
@@ -201,6 +201,16 @@ else
|
||||
fi
|
||||
export CGO_LDFLAGS
|
||||
|
||||
# For rust
|
||||
export RUST="@RUST@"
|
||||
export CARGO="@CARGO@"
|
||||
if [ -z "$RUSTFLAGS" ]; then
|
||||
RUSTFLAGS="-C link-args=-L$b/lib/.libs"
|
||||
else
|
||||
RUSTFLAGS="$RUSTFLAGS -C link-args=-L$b/lib/.libs"
|
||||
fi
|
||||
export RUSTFLAGS
|
||||
|
||||
# For GObject, Javascript and friends.
|
||||
export GJS="@GJS@"
|
||||
prepend GI_TYPELIB_PATH "$b/gobject"
|
||||
|
||||
3
rust/.gitignore
vendored
Normal file
3
rust/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
23
rust/Cargo.toml.in
Normal file
23
rust/Cargo.toml.in
Normal file
@@ -0,0 +1,23 @@
|
||||
# libguestfs Rust tests
|
||||
# Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
[package]
|
||||
name = "guestfs"
|
||||
version = "@VERSION@"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
45
rust/Makefile.am
Normal file
45
rust/Makefile.am
Normal file
@@ -0,0 +1,45 @@
|
||||
# libguestfs rust bindings
|
||||
# Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
generator_built = \
|
||||
src/bin/bindtests.rs \
|
||||
src/lib.rs
|
||||
|
||||
EXTRA_DIST = \
|
||||
.gitignore \
|
||||
$(generator_built) \
|
||||
tests/*.rs \
|
||||
src/*.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
|
||||
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
23
rust/run-bindtests
Executable file
23
rust/run-bindtests
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh -
|
||||
# libguestfs Rust bindings
|
||||
# Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
#
|
||||
# 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
|
||||
21
rust/run-tests
Executable file
21
rust/run-tests
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh -
|
||||
# libguestfs Rust tests
|
||||
# Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
#
|
||||
# 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
|
||||
121
rust/src/base.rs
Normal file
121
rust/src/base.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
use crate::error;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct guestfs_h {
|
||||
_unused: [u32; 0],
|
||||
}
|
||||
|
||||
#[link(name = "guestfs")]
|
||||
extern "C" {
|
||||
fn guestfs_create() -> *mut guestfs_h;
|
||||
fn guestfs_create_flags(flags: i64) -> *mut guestfs_h;
|
||||
fn guestfs_close(g: *mut guestfs_h);
|
||||
}
|
||||
|
||||
const GUESTFS_CREATE_NO_ENVIRONMENT: i64 = 1;
|
||||
const GUESTFS_CREATE_NO_CLOSE_ON_EXIT: i64 = 2;
|
||||
|
||||
pub struct Handle {
|
||||
pub(crate) g: *mut guestfs_h,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn create() -> Result<Handle, error::Error> {
|
||||
let g = unsafe { guestfs_create() };
|
||||
if g.is_null() {
|
||||
Err(error::Error::Create)
|
||||
} else {
|
||||
Ok(Handle { g })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_flags(flags: CreateFlags) -> Result<Handle, error::Error> {
|
||||
let g = unsafe { guestfs_create_flags(flags.to_libc_int()) };
|
||||
if g.is_null() {
|
||||
Err(error::Error::Create)
|
||||
} else {
|
||||
Ok(Handle { g })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
unsafe { guestfs_close(self.g) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateFlags {
|
||||
create_no_environment_flag: bool,
|
||||
create_no_close_on_exit_flag: bool,
|
||||
}
|
||||
|
||||
impl CreateFlags {
|
||||
pub fn none() -> CreateFlags {
|
||||
CreateFlags {
|
||||
create_no_environment_flag: false,
|
||||
create_no_close_on_exit_flag: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> CreateFlags {
|
||||
CreateFlags::none()
|
||||
}
|
||||
|
||||
pub fn create_no_environment(mut self, flag: bool) -> CreateFlags {
|
||||
self.create_no_environment_flag = flag;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn create_no_close_on_exit_flag(mut self, flag: bool) -> CreateFlags {
|
||||
self.create_no_close_on_exit_flag = flag;
|
||||
self
|
||||
}
|
||||
|
||||
unsafe fn to_libc_int(self) -> i64 {
|
||||
let mut flag = 0;
|
||||
flag |= if self.create_no_environment_flag {
|
||||
GUESTFS_CREATE_NO_ENVIRONMENT
|
||||
} else {
|
||||
0
|
||||
};
|
||||
flag |= if self.create_no_close_on_exit_flag {
|
||||
GUESTFS_CREATE_NO_CLOSE_ON_EXIT
|
||||
} else {
|
||||
0
|
||||
};
|
||||
flag
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UUID {
|
||||
uuid: [u8; 32],
|
||||
}
|
||||
|
||||
impl UUID {
|
||||
pub(crate) fn new(uuid: [u8; 32]) -> UUID {
|
||||
UUID { uuid }
|
||||
}
|
||||
pub fn to_bytes(self) -> [u8; 32] {
|
||||
self.uuid
|
||||
}
|
||||
}
|
||||
0
rust/src/bin/.gitkeep
Normal file
0
rust/src/bin/.gitkeep
Normal file
70
rust/src/error.rs
Normal file
70
rust/src/error.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
use crate::base;
|
||||
use crate::utils;
|
||||
use std::convert;
|
||||
use std::ffi;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::str;
|
||||
|
||||
#[link(name = "guestfs")]
|
||||
extern "C" {
|
||||
fn guestfs_last_error(g: *mut base::guestfs_h) -> *const c_char;
|
||||
fn guestfs_last_errno(g: *mut base::guestfs_h) -> c_int;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct APIError {
|
||||
operation: &'static str,
|
||||
message: String,
|
||||
errno: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
API(APIError),
|
||||
IllegalString(ffi::NulError),
|
||||
Utf8Error(str::Utf8Error),
|
||||
Create,
|
||||
}
|
||||
|
||||
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 base::Handle {
|
||||
pub(crate) fn get_error_from_handle(&self, operation: &'static str) -> Error {
|
||||
let c_msg = unsafe { guestfs_last_error(self.g) };
|
||||
let message = unsafe { utils::char_ptr_to_string(c_msg).unwrap() };
|
||||
let errno = unsafe { guestfs_last_errno(self.g) };
|
||||
Error::API(APIError {
|
||||
operation,
|
||||
message,
|
||||
errno,
|
||||
})
|
||||
}
|
||||
}
|
||||
26
rust/src/lib.rs
Normal file
26
rust/src/lib.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
mod base;
|
||||
mod error;
|
||||
mod guestfs;
|
||||
mod utils;
|
||||
|
||||
pub use crate::base::*;
|
||||
pub use crate::error::*;
|
||||
pub use crate::guestfs::*;
|
||||
146
rust/src/utils.rs
Normal file
146
rust/src/utils.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
use crate::error;
|
||||
use std::collections;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::str;
|
||||
|
||||
extern "C" {
|
||||
fn free(buf: *const c_void);
|
||||
}
|
||||
|
||||
pub(crate) struct NullTerminatedIter<T: Copy + Clone> {
|
||||
p: *const *const T,
|
||||
}
|
||||
|
||||
impl<T: Copy + Clone> NullTerminatedIter<T> {
|
||||
pub(crate) fn new(p: *const *const T) -> NullTerminatedIter<T> {
|
||||
NullTerminatedIter { p }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Clone> Iterator for NullTerminatedIter<T> {
|
||||
type Item = *const T;
|
||||
fn next(&mut self) -> Option<*const T> {
|
||||
let r = unsafe { *(self.p) };
|
||||
if r.is_null() {
|
||||
None
|
||||
} else {
|
||||
self.p = unsafe { self.p.offset(1) };
|
||||
Some(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct RawList<T> {
|
||||
size: u32,
|
||||
ptr: *const T,
|
||||
}
|
||||
|
||||
pub(crate) struct RawListIter<'a, T> {
|
||||
current: u32,
|
||||
list: &'a RawList<T>,
|
||||
}
|
||||
|
||||
impl<T> RawList<T> {
|
||||
fn iter<'a>(&'a self) -> RawListIter<'a, T> {
|
||||
RawListIter {
|
||||
current: 0,
|
||||
list: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for RawListIter<'a, T> {
|
||||
type Item = *const T;
|
||||
fn next(&mut self) -> Option<*const T> {
|
||||
if self.current >= self.list.size {
|
||||
None
|
||||
} else {
|
||||
let elem = unsafe { self.list.ptr.offset(self.current as isize) };
|
||||
self.current += 1;
|
||||
Some(elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn arg_string_list(v: &[&str]) -> Result<Vec<ffi::CString>, error::Error> {
|
||||
let mut w = Vec::new();
|
||||
for x in v.iter() {
|
||||
let y: &str = x;
|
||||
w.push(ffi::CString::new(y)?);
|
||||
}
|
||||
Ok(w)
|
||||
}
|
||||
|
||||
pub(crate) fn free_string_list(l: *const *const c_char) {
|
||||
for buf in NullTerminatedIter::new(l) {
|
||||
unsafe { free(buf as *const c_void) };
|
||||
}
|
||||
unsafe { free(l as *const c_void) };
|
||||
}
|
||||
|
||||
pub(crate) fn hashmap(
|
||||
l: *const *const c_char,
|
||||
) -> Result<collections::HashMap<String, String>, error::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 { char_ptr_to_string(key) }?;
|
||||
let val = unsafe { char_ptr_to_string(val) }?;
|
||||
map.insert(key, val);
|
||||
} else {
|
||||
// Internal Error -> panic
|
||||
panic!("odd number of items in hash table");
|
||||
}
|
||||
}
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
pub(crate) fn struct_list<T, S: TryFrom<*const T, Error = error::Error>>(
|
||||
l: *const RawList<T>,
|
||||
) -> Result<Vec<S>, error::Error> {
|
||||
let mut v = Vec::new();
|
||||
for x in unsafe { &*l }.iter() {
|
||||
v.push(S::try_from(x)?);
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub(crate) fn string_list(l: *const *const c_char) -> Result<Vec<String>, error::Error> {
|
||||
let mut v = Vec::new();
|
||||
for x in NullTerminatedIter::new(l) {
|
||||
let s = unsafe { char_ptr_to_string(x) }?;
|
||||
v.push(s);
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn char_ptr_to_string(ptr: *const c_char) -> Result<String, str::Utf8Error> {
|
||||
fn char_ptr_to_string_inner(ptr: *const c_char) -> Result<String, str::Utf8Error> {
|
||||
let s = unsafe { ffi::CStr::from_ptr(ptr) };
|
||||
let s = s.to_str()?.to_string();
|
||||
Ok(s)
|
||||
}
|
||||
char_ptr_to_string_inner(ptr)
|
||||
}
|
||||
24
rust/tests/010_load.rs
Normal file
24
rust/tests/010_load.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 load() {
|
||||
// nop
|
||||
}
|
||||
24
rust/tests/020_create.rs
Normal file
24
rust/tests/020_create.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 create() {
|
||||
guestfs::Handle::create().unwrap();
|
||||
}
|
||||
30
rust/tests/030_create_flags.rs
Normal file
30
rust/tests/030_create_flags.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 guestfs::*;
|
||||
|
||||
#[test]
|
||||
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 _h = Handle::create_flags(flags).expect("create_flags fail");
|
||||
// TODO: Add parse_environment to check the flag is created correctly
|
||||
}
|
||||
38
rust/tests/040_create_multiple.rs
Normal file
38
rust/tests/040_create_multiple.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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;
|
||||
|
||||
fn create() -> guestfs::Handle {
|
||||
match guestfs::Handle::create() {
|
||||
Ok(g) => g,
|
||||
Err(e) => panic!("fail: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
fn ignore(_x: guestfs::Handle, _y: guestfs::Handle, _z: guestfs::Handle) {
|
||||
// drop
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_multiple() {
|
||||
let x = create();
|
||||
let y = create();
|
||||
let z = create();
|
||||
ignore(x, y, z)
|
||||
}
|
||||
62
rust/tests/050_handle_properties.rs
Normal file
62
rust/tests/050_handle_properties.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 verbose() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.set_verbose(true).expect("set_verbose");
|
||||
assert_eq!(g.get_verbose().expect("get_verbose"), true);
|
||||
g.set_verbose(false).expect("set_verbose");
|
||||
assert_eq!(g.get_verbose().expect("get_verbose"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.set_trace(true).expect("set_trace");
|
||||
assert_eq!(g.get_trace().expect("get_trace"), true);
|
||||
g.set_trace(false).expect("set_trace");
|
||||
assert_eq!(g.get_trace().expect("get_trace"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn autosync() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.set_autosync(true).expect("set_autosync");
|
||||
assert_eq!(g.get_autosync().expect("get_autosync"), true);
|
||||
g.set_autosync(false).expect("set_autosync");
|
||||
assert_eq!(g.get_autosync().expect("get_autosync"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.set_path(Some(".")).expect("set_path");
|
||||
assert_eq!(g.get_path().expect("get_path"), ".");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_drive() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.add_drive("/dev/null", Default::default())
|
||||
.expect("add_drive");
|
||||
}
|
||||
41
rust/tests/070_opt_args.rs
Normal file
41
rust/tests/070_opt_args.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 no_optargs() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.add_drive("/dev/null", Default::default())
|
||||
.expect("add_drive");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_optarg() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
g.add_drive(
|
||||
"/dev/null",
|
||||
guestfs::AddDriveOptArgs {
|
||||
readonly: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.expect("add_drive");
|
||||
}
|
||||
26
rust/tests/080_version.rs
Normal file
26
rust/tests/080_version.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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 version() {
|
||||
let g = guestfs::Handle::create().expect("create");
|
||||
let v = g.version().expect("version");
|
||||
assert_eq!(v.major, 1)
|
||||
}
|
||||
61
rust/tests/090_ret_values.rs
Normal file
61
rust/tests/090_ret_values.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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)
|
||||
}
|
||||
65
rust/tests/100_launch.rs
Normal file
65
rust/tests/100_launch.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
/* libguestfs Rust bindings
|
||||
* Copyright (C) 2019 Hiroyuki Katsura <hiroyuki.katsura.0513@gmail.com>
|
||||
*
|
||||
* 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");
|
||||
}
|
||||
Reference in New Issue
Block a user