1use anyhow::Context;
4use anyhow::Result;
5use serde::Deserialize;
6use serde::Serialize;
7use std::io::Write;
8use std::ops::Range;
9use std::path::Path;
10use std::path::PathBuf;
11
12#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Default)]
13pub struct Metrics {
14 pub thunk_count: u64,
16}
17
18#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
19pub struct Layout {
20 pub files: Vec<InputFile>,
22
23 #[serde(default)]
25 pub metrics: Metrics,
26}
27
28#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
29pub struct InputFile {
30 pub path: PathBuf,
33
34 pub archive_entry: Option<ArchiveEntryInfo>,
37
38 pub sections: Vec<Option<Section>>,
41
42 pub temporary: bool,
45}
46
47#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
48pub struct ArchiveEntryInfo {
49 pub range: Range<usize>,
51
52 pub identifier: Vec<u8>,
53}
54
55#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
56pub struct Section {
57 pub mem_range: Range<u64>,
58}
59
60impl Layout {
61 pub fn write(&self, writer: &mut impl Write) -> Result<()> {
62 postcard::to_io(self, writer)?;
63 Ok(())
64 }
65
66 pub fn to_bytes(&self) -> Result<Vec<u8>> {
67 Ok(postcard::to_stdvec(self)?)
68 }
69
70 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
71 postcard::from_bytes(bytes).context("Invalid linker layout")
72 }
73}
74
75#[must_use]
76pub fn layout_path(base_path: &Path) -> PathBuf {
77 let mut s = base_path.as_os_str().to_owned();
80 s.push(".layout");
81 PathBuf::from(s)
82}
83
84impl std::fmt::Display for InputFile {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 self.path.display().fmt(f)?;
87 if let Some(e) = self.archive_entry.as_ref() {
88 write!(f, " @ {}", String::from_utf8_lossy(&e.identifier))?;
89 }
90 Ok(())
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_round_trip() {
100 let layout = Layout {
101 files: vec![InputFile {
102 path: PathBuf::new(),
103 archive_entry: None,
104 sections: vec![Some(Section { mem_range: 42..48 })],
105 temporary: true,
106 }],
107 metrics: Metrics { thunk_count: 3 },
108 };
109 let bytes = layout.to_bytes().unwrap();
110 let layout2 = Layout::from_bytes(&bytes).unwrap();
111 assert_eq!(layout, layout2);
112 }
113}