Skip to content
This repository was archived by the owner on Nov 6, 2024. It is now read-only.

Commit b8e3fa7

Browse files
author
Alexandra Iordache
committed
serde serialization, conditionally compiled
Serde is pulled in as a conditional dependency, activated by the with_serde feature. If active, this feature will also generate sources that implement serde::Serialize and serde::Deserialize for all generated bindings. The implementation (de)serializes each struct/union's raw bytes, as all of them are FFI-safe. Signed-off-by: Alexandra Iordache <[email protected]>
1 parent 59b969f commit b8e3fa7

File tree

7 files changed

+278
-0
lines changed

7 files changed

+278
-0
lines changed

Cargo.lock

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ repository = "https://github.com/rust-vmm/kvm-bindings"
77
readme = "README.md"
88
keywords = ["kvm"]
99
license = "Apache-2.0"
10+
build = "build.rs"
1011

1112
[features]
1213
kvm-v4_14_0 = []
1314
kvm-v4_20_0 = []
15+
with_serde = ["libc", "serde", "serde_bytes"]
1416

1517
[dependencies]
18+
libc = { version = ">=0.2.39", optional = true }
19+
serde = { version = ">=1.0.27", optional = true }
20+
serde_bytes = { version = ">=0.11.2", optional = true }

build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#[cfg(feature = "with_serde")]
5+
include!("build_serde.rs");
6+
7+
#[cfg(not(feature = "with_serde"))]
8+
fn main() {}

build_serde.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use std::env;
5+
use std::fs::{self, DirEntry, File, OpenOptions};
6+
use std::io::{self, BufRead, BufReader, Read, Write};
7+
use std::path::{Component, Path, PathBuf};
8+
9+
const SER_HDR: &str = "serialization/header.rs.txt";
10+
const SER_SRC: &str = "serialization/src/";
11+
const SER_TPL: &str = "serialization/template.rs.txt";
12+
13+
fn main() {
14+
let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
15+
add_serialization(&root);
16+
}
17+
18+
fn add_serialization(root: &Path) {
19+
let srcdir = root.join("src");
20+
let archs = ["arm", "arm64", "x86"];
21+
22+
for arch in archs.into_iter().map(|a| srcdir.join(a)) {
23+
visit_dirs(&arch, &add_serialization_to_srcfile).unwrap();
24+
}
25+
}
26+
27+
fn visit_dirs(dir: &Path, bindings_visitor: &dyn Fn(&DirEntry)) -> io::Result<()> {
28+
if dir.is_dir() {
29+
for entry in fs::read_dir(dir)? {
30+
let entry = entry?;
31+
let path = entry.path();
32+
if path.is_file()
33+
&& path
34+
.file_name()
35+
.unwrap()
36+
.to_str()
37+
.unwrap()
38+
.starts_with("bindings_")
39+
{
40+
bindings_visitor(&entry)
41+
}
42+
}
43+
}
44+
Ok(())
45+
}
46+
47+
fn is_relevant(line: &str) -> bool {
48+
for prefix in vec!["pub struct", "pub union"].iter() {
49+
if line.starts_with(prefix) {
50+
for blacklisted in vec!["__BindgenBitfieldUnit", "__IncompleteArrayField"].iter() {
51+
if line.contains(blacklisted) {
52+
return false;
53+
}
54+
}
55+
return true;
56+
}
57+
}
58+
return false;
59+
}
60+
61+
fn add_serialization_to_srcfile(srcfile: &DirEntry) {
62+
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
63+
let root = Path::new(&manifest_dir);
64+
65+
let serialization_header_file = root.join(SER_HDR);
66+
let mut header = String::from("");
67+
let _ = File::open(serialization_header_file)
68+
.unwrap()
69+
.read_to_string(&mut header);
70+
71+
let template_file = root.join(SER_TPL);
72+
let mut template = String::from("");
73+
let _ = File::open(template_file)
74+
.unwrap()
75+
.read_to_string(&mut template);
76+
77+
let srcpath = srcfile.path();
78+
let mut components = srcpath.components().rev();
79+
80+
if let Some(Component::Normal(filename)) = components.next() {
81+
if let Some(Component::Normal(arch)) = components.next() {
82+
let serializer_fname = format!(
83+
"serializers_{}",
84+
&filename.to_str().unwrap()["bindings_".len()..]
85+
);
86+
87+
let arch_dir_str = format!("{}/{}/{}", env::var("OUT_DIR").unwrap(), SER_SRC, arch.to_str().unwrap());
88+
let arch_dir = Path::new(arch_dir_str.as_str());
89+
if !arch_dir.exists() {
90+
fs::create_dir_all(arch_dir).unwrap();
91+
} else if !arch_dir.is_dir() {
92+
panic!("{:?} exists and is not a directory", arch_dir);
93+
}
94+
95+
let mut srcfile_out = OpenOptions::new()
96+
.create(true)
97+
.truncate(true)
98+
.write(true)
99+
.open(arch_dir.join(serializer_fname))
100+
.unwrap();
101+
srcfile_out.write_all(header.as_bytes()).unwrap();
102+
103+
let srcfile_in = File::open(srcfile.path()).unwrap();
104+
let reader = BufReader::new(srcfile_in);
105+
for line_res in reader.lines() {
106+
if let Ok(line) = line_res {
107+
if is_relevant(&line) {
108+
let datastruct_name = line.split_whitespace().collect::<Vec<&str>>()[2];
109+
let impl_text = template.replace("TYPENAME", datastruct_name);
110+
srcfile_out.write_all(impl_text.as_bytes()).unwrap();
111+
}
112+
}
113+
}
114+
}
115+
}
116+
}

serialization/header.rs.txt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use std::mem;
5+
use std::ptr;
6+
7+
use serde::de::{Deserialize, Deserializer};
8+
use serde::{Serialize, Serializer};
9+
use serde_bytes::ByteBuf;
10+
11+
fn serialize_ffi<T>(something: &T) -> ByteBuf {
12+
let mut serialized_self: Vec<u8> = vec![0; mem::size_of::<T>()];
13+
unsafe {
14+
libc::memcpy(
15+
serialized_self.as_mut_ptr() as *mut libc::c_void,
16+
something as *const T as *const libc::c_void,
17+
mem::size_of::<T>(),
18+
);
19+
}
20+
ByteBuf::from(serialized_self)
21+
}
22+
23+
fn deserialize_ffi<T>(serialized: ByteBuf) -> T {
24+
unsafe { ptr::read(serialized.into_vec().as_ptr() as *const T) }
25+
}
26+
27+
impl<Storage, Align> Serialize for __BindgenBitfieldUnit<Storage, Align>
28+
where
29+
Storage: AsRef<[u8]> + AsMut<[u8]>,
30+
{
31+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
32+
where
33+
S: Serializer,
34+
{
35+
let bytes = serialize_ffi::<__BindgenBitfieldUnit<Storage, Align>>(&self);
36+
bytes.serialize(serializer)
37+
}
38+
}
39+
40+
impl<'de, Storage, Align> Deserialize<'de> for __BindgenBitfieldUnit<Storage, Align>
41+
where
42+
Storage: AsRef<[u8]> + AsMut<[u8]>,
43+
{
44+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
45+
where
46+
D: Deserializer<'de>,
47+
{
48+
let v: ByteBuf = ByteBuf::deserialize::<D>(deserializer)?;
49+
Ok(deserialize_ffi::<__BindgenBitfieldUnit<Storage, Align>>(v))
50+
}
51+
}
52+
53+
impl<T> Serialize for __IncompleteArrayField<T> {
54+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
55+
where
56+
S: Serializer,
57+
{
58+
[0u8; 0].serialize(serializer)
59+
}
60+
}
61+
62+
impl<'de, T> Deserialize<'de> for __IncompleteArrayField<T> {
63+
fn deserialize<D>(_: D) -> std::result::Result<Self, D::Error>
64+
where
65+
D: Deserializer<'de>,
66+
{
67+
Ok(__IncompleteArrayField::new())
68+
}
69+
}

serialization/template.rs.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
impl Serialize for TYPENAME {
2+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
3+
where
4+
S: Serializer,
5+
{
6+
let bytes = serialize_ffi::<TYPENAME>(&self);
7+
bytes.serialize(serializer)
8+
}
9+
}
10+
11+
impl<'de> Deserialize<'de> for TYPENAME {
12+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
13+
where
14+
D: Deserializer<'de>,
15+
{
16+
let v: ByteBuf = ByteBuf::deserialize::<D>(deserializer)?;
17+
Ok(deserialize_ffi::<TYPENAME>(v))
18+
}
19+
}

src/lib.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
#![allow(non_camel_case_types)]
66
#![allow(non_snake_case)]
77

8+
#[cfg(feature = "with_serde")]
9+
extern crate libc;
10+
#[cfg(feature = "with_serde")]
11+
extern crate serde;
12+
#[cfg(feature = "with_serde")]
13+
extern crate serde_bytes;
14+
815
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
916
mod x86;
1017
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -19,3 +26,28 @@ pub use self::arm::bindings::*;
1926
mod arm64;
2027
#[cfg(target_arch = "aarch64")]
2128
pub use self::arm64::bindings::*;
29+
30+
31+
// Serializers for x86 and x86_64.
32+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_14_0", any(target_arch = "x86", target_arch = "x86_64")))]
33+
include!(concat!(env!("OUT_DIR"), "/serialization/src/x86/serializers_v4_14_0.rs"));
34+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_20_0", any(target_arch = "x86", target_arch = "x86_64")))]
35+
include!(concat!(env!("OUT_DIR"), "/serialization/src/x86/serializers_v4_20_0.rs"));
36+
#[cfg(all(feature = "with_serde", not(feature = "kvm-v4_14_0"), not(feature = "kvm-v4_20_0"), any(target_arch = "x86", target_arch = "x86_64")))]
37+
include!(concat!(env!("OUT_DIR"), "/serialization/src/x86/serializers_v4_20_0.rs"));
38+
39+
// Serializers for aarch.
40+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_14_0", target_arch = "aarch"))]
41+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm/serializers_v4_14_0.rs"));
42+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_20_0", target_arch = "aarch"))]
43+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm/serializers_v4_20_0.rs"));
44+
#[cfg(all(feature = "with_serde", not(feature = "kvm-v4_14_0"), not(feature = "kvm-v4_20_0"), target_arch = "aarch"))]
45+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm/serializers_v4_20_0.rs"));
46+
47+
// Serializers for aarch64.
48+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_14_0", target_arch = "aarch64"))]
49+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm64/serializers_v4_14_0.rs"));
50+
#[cfg(all(feature = "with_serde", feature = "kvm-v4_20_0", target_arch = "aarch64"))]
51+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm64/serializers_v4_20_0.rs"));
52+
#[cfg(all(feature = "with_serde", not(feature = "kvm-v4_14_0"), not(feature = "kvm-v4_20_0"), target_arch = "aarch64"))]
53+
include!(concat!(env!("OUT_DIR"), "/serialization/src/arm64/serializers_v4_20_0.rs"));

0 commit comments

Comments
 (0)