blob: d69ce1522cc2f7c95959f3a65db8078444036567 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Representation of the virtual_device metadata.
mod manifest;
mod v1;
pub use manifest::*;
pub use v1::*;
use anyhow::{Context, Result};
use camino::Utf8Path;
use serde::{Deserialize, Serialize};
use std::fs::File;
const VIRTUAL_DEVICE_SCHEMA_V1: &str =
"http://fuchsia.com/schemas/sdk/virtual_device-93A41932.json";
/// Private helper for deserializing the virtual device.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
enum SerializationHelper {
V1 { schema_id: String, data: VirtualDeviceV1 },
}
/// Versioned virtual device specification.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum VirtualDevice {
V1(VirtualDeviceV1),
}
impl VirtualDevice {
/// Load a VirtualDevice from a path on disk.
pub fn try_load_from(path: impl AsRef<Utf8Path>) -> Result<Self> {
let name = path.as_ref().file_stem().with_context(|| {
format!("Can't determine device name based on provided path: '{}'", path.as_ref())
})?;
let file = File::open(path.as_ref())
.with_context(|| format!("opening virtual device: {:?}", path.as_ref()))?;
let helper: SerializationHelper =
serde_json::from_reader(file).context("parsing virtual device")?;
let device = match helper {
SerializationHelper::V1 { schema_id: _, mut data } => {
// Use the filename as the device name instead of the name
// originally in the file.
// TODO: Why are we doing this?
data.name = name.to_string();
VirtualDevice::V1(data)
}
};
Ok(device)
}
/// Write a virtual device to disk at `path`.
pub fn write(&self, path: impl AsRef<Utf8Path>) -> Result<()> {
let helper = match self {
Self::V1(data) => SerializationHelper::V1 {
schema_id: VIRTUAL_DEVICE_SCHEMA_V1.into(),
data: data.clone(),
},
};
let file = File::create(path.as_ref()).context("creating virtual device file")?;
serde_json::to_writer(file, &helper).context("writing virtual device file")?;
Ok(())
}
/// Returns VirtualDevice entry name.
pub fn name(&self) -> &str {
match self {
Self::V1(device) => &device.name.as_str(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use tempfile::TempDir;
#[test]
fn test_parse_v1() {
let tmp = TempDir::new().unwrap();
let vd_path = Utf8Path::from_path(tmp.path()).unwrap().join("virtual_device.json");
let vd_file = File::create(&vd_path).unwrap();
serde_json::to_writer(
&vd_file,
&json!({
"schema_id": "http://fuchsia.com/schemas/sdk/virtual_device-93A41932.json",
"data": {
"name": "generic-x64",
"type": "virtual_device",
"hardware": {
"audio": {
"model": "hda"
},
"cpu": {
"arch": "x64"
},
"inputs": {
"pointing_device": "touch"
},
"window_size": {
"width": 640,
"height": 480,
"units": "pixels"
},
"memory": {
"quantity": 1,
"units": "gigabytes"
},
"storage": {
"quantity": 1,
"units": "gigabytes"
}
},
"start_up_args_template": "/path/to/args"
}
}),
)
.unwrap();
let vd = VirtualDevice::try_load_from(vd_path).unwrap();
assert!(matches!(vd, VirtualDevice::V1 { .. }));
assert_eq!(vd.name(), "virtual_device");
}
}