aboutsummaryrefslogtreecommitdiffstats
path: root/liblfvm/serialize.ccm
blob: 4b7ed516ebfa34121a8ab2e348f349d2aed37aae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * This source code is released into the public domain.
 */

module;

#include <format>
#include <stdexcept>
#include <string>

import nihil;
import nihil.ucl;

export module liblfvm:serialize;

import :vm_config;

namespace lfvm {

/*
 * Exception thrown when (de)serialization fails.
 */
export struct serialization_error final : std::runtime_error
{
	serialization_error(std::string what)
		: std::runtime_error(std::move(what))
	{
	}
};

// Convert a vm_config to a UCL string.
export auto serialize(vm_config const &config) -> std::string
{
	using namespace nihil::ucl;
	using namespace std::literals;

	auto uobj = map<object>();

	uobj.insert({"name"sv, string(config.name())});
	uobj.insert({"uuid"sv, string(to_string(config.uuid()))});
	uobj.insert({"ncpus"sv, integer(config.ncpus())});
	uobj.insert({"memory_size"sv, integer(config.memory_size())});
	uobj.insert({"destroy_on_poweroff"sv,
		integer(config.destroy_on_poweroff())});
	uobj.insert({"wire_memory"sv,
		integer(config.wire_memory())});
	uobj.insert({"include_memory_in_core"sv,
		integer(config.include_memory_in_core())});
	uobj.insert({"yield_on_halt"sv, integer(config.yield_on_halt())});
	uobj.insert({"exit_on_pause"sv, integer(config.yield_on_halt())});
	uobj.insert({"rtc_is_utc"sv, integer(config.rtc_is_utc())});

	return std::format("{:c}", uobj);
}

// Convert a UCL string to a vm_config.
export auto deserialize(std::string_view text) -> vm_config
{
	using namespace nihil::ucl;

	auto uobj = parse(text);

	// Name
	auto name_obj = uobj.find("name");
	if (!name_obj)
		throw serialization_error("missing name");
	auto name = std::string();
	try {
		name = object_cast<string>(*name_obj).value();
	} catch (type_mismatch const &) {
		throw serialization_error("invalid name");
	}
	
	auto vm = vm_config(name);

	// UUID
	auto uuid_obj = uobj.find("uuid");
	if (!uuid_obj)
		throw serialization_error("missing uuid");
	try {
		auto uuid_str = object_cast<string>(*uuid_obj);
		auto uuid = nihil::uuid::from_string(uuid_str.value());
		if (!uuid)
			throw serialization_error("invalid uuid");
		vm.uuid(*uuid);
	} catch (type_mismatch const &) {
		throw serialization_error("invalid uuid");
	}

	if (auto obj = uobj.find("ncpus"); obj) try {
		vm.ncpus(object_cast<integer>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid ncpus");
	}

	if (auto obj = uobj.find("memory"); obj) try {
		vm.memory_size(object_cast<integer>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid memory");
	}

	if (auto obj = uobj.find("destroy_on_poweroff"); obj) try {
		vm.destroy_on_poweroff(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid destroy_on_poweroff");
	}

	if (auto obj = uobj.find("wire_memory"); obj) try {
		vm.wire_memory(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid wire_memory");
	}

	if (auto obj = uobj.find("include_memory_in_core"); obj) try {
		vm.include_memory_in_core(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid include_memory_in_core");
	}

	if (auto obj = uobj.find("yield_on_halt"); obj) try {
		vm.yield_on_halt(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid yield_on_halt");
	}

	if (auto obj = uobj.find("exit_on_pause"); obj) try {
		vm.exit_on_pause(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid exit_on_pause");
	}

	if (auto obj = uobj.find("rtc_is_utc"); obj) try {
		vm.rtc_is_utc(object_cast<boolean>(*obj).value());
	} catch (type_mismatch const &) {
		throw serialization_error("invalid rtc_is_utc");
	}

	return vm;
}

} // namespace lfvm