Skip to content

Commit e8de35b

Browse files
committed
Make objdiff-core no_std + huge WASM rework
1 parent d938988 commit e8de35b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1461
-1044
lines changed

Cargo.lock

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

objdiff-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ supports-color = "3.0"
2828
time = { version = "0.3", features = ["formatting", "local-offset"] }
2929
tracing = "0.1"
3030
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
31+
typed-path = "0.10"
3132

3233
[target.'cfg(target_env = "musl")'.dependencies]
3334
mimalloc = "0.1"

objdiff-cli/src/cmd/diff.rs

Lines changed: 127 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::{
2-
fs,
32
io::stdout,
43
mem,
5-
path::{Path, PathBuf},
64
str::FromStr,
75
sync::{
86
atomic::{AtomicBool, Ordering},
@@ -27,7 +25,11 @@ use objdiff_core::{
2725
watcher::{create_watcher, Watcher},
2826
BuildConfig,
2927
},
30-
config::{build_globset, ProjectConfig, ProjectObject},
28+
config::{
29+
build_globset,
30+
path::{check_path_buf, platform_path, platform_path_serde_option},
31+
ProjectConfig, ProjectObject, ProjectObjectMetadata,
32+
},
3133
diff,
3234
diff::{
3335
ConfigEnum, ConfigPropertyId, ConfigPropertyKind, DiffObjConfig, MappingConfig, ObjDiff,
@@ -40,6 +42,7 @@ use objdiff_core::{
4042
obj::ObjInfo,
4143
};
4244
use ratatui::prelude::*;
45+
use typed_path::{Utf8PlatformPath, Utf8PlatformPathBuf};
4346

4447
use crate::{
4548
util::{
@@ -53,21 +56,21 @@ use crate::{
5356
/// Diff two object files. (Interactive or one-shot mode)
5457
#[argp(subcommand, name = "diff")]
5558
pub struct Args {
56-
#[argp(option, short = '1')]
59+
#[argp(option, short = '1', from_str_fn(platform_path))]
5760
/// Target object file
58-
target: Option<PathBuf>,
59-
#[argp(option, short = '2')]
61+
target: Option<Utf8PlatformPathBuf>,
62+
#[argp(option, short = '2', from_str_fn(platform_path))]
6063
/// Base object file
61-
base: Option<PathBuf>,
62-
#[argp(option, short = 'p')]
64+
base: Option<Utf8PlatformPathBuf>,
65+
#[argp(option, short = 'p', from_str_fn(platform_path))]
6366
/// Project directory
64-
project: Option<PathBuf>,
67+
project: Option<Utf8PlatformPathBuf>,
6568
#[argp(option, short = 'u')]
6669
/// Unit name within project
6770
unit: Option<String>,
68-
#[argp(option, short = 'o')]
71+
#[argp(option, short = 'o', from_str_fn(platform_path))]
6972
/// Output file (one-shot mode) ("-" for stdout)
70-
output: Option<PathBuf>,
73+
output: Option<Utf8PlatformPathBuf>,
7174
#[argp(option)]
7275
/// Output format (json, json-pretty, proto) (default: json)
7376
format: Option<String>,
@@ -89,86 +92,61 @@ pub struct Args {
8992
}
9093

9194
pub fn run(args: Args) -> Result<()> {
92-
let (target_path, base_path, project_config) = match (
93-
&args.target,
94-
&args.base,
95-
&args.project,
96-
&args.unit,
97-
) {
98-
(Some(_), Some(_), None, None)
99-
| (Some(_), None, None, None)
100-
| (None, Some(_), None, None) => (args.target.clone(), args.base.clone(), None),
101-
(None, None, p, u) => {
102-
let project = match p {
103-
Some(project) => project.clone(),
104-
_ => std::env::current_dir().context("Failed to get the current directory")?,
105-
};
106-
let Some((project_config, project_config_info)) =
107-
objdiff_core::config::try_project_config(&project)
108-
else {
109-
bail!("Project config not found in {}", &project.display())
110-
};
111-
let mut project_config = project_config.with_context(|| {
112-
format!("Reading project config {}", project_config_info.path.display())
113-
})?;
114-
let object = {
115-
let resolve_paths = |o: &mut ProjectObject| {
116-
o.resolve_paths(
117-
&project,
118-
project_config.target_dir.as_deref(),
119-
project_config.base_dir.as_deref(),
95+
let (target_path, base_path, project_config) =
96+
match (&args.target, &args.base, &args.project, &args.unit) {
97+
(Some(_), Some(_), None, None)
98+
| (Some(_), None, None, None)
99+
| (None, Some(_), None, None) => (args.target.clone(), args.base.clone(), None),
100+
(None, None, p, u) => {
101+
let project = match p {
102+
Some(project) => project.clone(),
103+
_ => check_path_buf(
104+
std::env::current_dir().context("Failed to get the current directory")?,
120105
)
106+
.context("Current directory is not valid UTF-8")?,
121107
};
122-
if let Some(u) = u {
123-
let unit_path =
124-
PathBuf::from_str(u).ok().and_then(|p| fs::canonicalize(p).ok());
125-
126-
let Some(object) = project_config
127-
.units
128-
.as_deref_mut()
129-
.unwrap_or_default()
130-
.iter_mut()
131-
.find_map(|obj| {
132-
if obj.name.as_deref() == Some(u) {
133-
resolve_paths(obj);
134-
return Some(obj);
135-
}
136-
137-
let up = unit_path.as_deref()?;
138-
139-
resolve_paths(obj);
140-
141-
if [&obj.base_path, &obj.target_path]
142-
.into_iter()
143-
.filter_map(|p| p.as_ref().and_then(|p| p.canonicalize().ok()))
144-
.any(|p| p == up)
145-
{
146-
return Some(obj);
147-
}
148-
149-
None
150-
})
151-
else {
152-
bail!("Unit not found: {}", u)
153-
};
154-
155-
object
108+
let Some((project_config, project_config_info)) =
109+
objdiff_core::config::try_project_config(project.as_ref())
110+
else {
111+
bail!("Project config not found in {}", &project)
112+
};
113+
let project_config = project_config.with_context(|| {
114+
format!("Reading project config {}", project_config_info.path.display())
115+
})?;
116+
let target_obj_dir = project_config
117+
.target_dir
118+
.as_ref()
119+
.map(|p| project.join(p.with_platform_encoding()));
120+
let base_obj_dir = project_config
121+
.base_dir
122+
.as_ref()
123+
.map(|p| project.join(p.with_platform_encoding()));
124+
let objects = project_config
125+
.units
126+
.iter()
127+
.flatten()
128+
.map(|o| {
129+
ObjectConfig::new(
130+
o,
131+
&project,
132+
target_obj_dir.as_deref(),
133+
base_obj_dir.as_deref(),
134+
)
135+
})
136+
.collect::<Vec<_>>();
137+
let object = if let Some(u) = u {
138+
objects
139+
.iter()
140+
.find(|obj| obj.name == *u)
141+
.ok_or_else(|| anyhow!("Unit not found: {}", u))?
156142
} else if let Some(symbol_name) = &args.symbol {
157143
let mut idx = None;
158144
let mut count = 0usize;
159-
for (i, obj) in project_config
160-
.units
161-
.as_deref_mut()
162-
.unwrap_or_default()
163-
.iter_mut()
164-
.enumerate()
165-
{
166-
resolve_paths(obj);
167-
145+
for (i, obj) in objects.iter().enumerate() {
168146
if obj
169147
.target_path
170148
.as_deref()
171-
.map(|o| obj::read::has_function(o, symbol_name))
149+
.map(|o| obj::read::has_function(o.as_ref(), symbol_name))
172150
.transpose()?
173151
.unwrap_or(false)
174152
{
@@ -181,7 +159,7 @@ pub fn run(args: Args) -> Result<()> {
181159
}
182160
match (count, idx) {
183161
(0, None) => bail!("Symbol not found: {}", symbol_name),
184-
(1, Some(i)) => &mut project_config.units_mut()[i],
162+
(1, Some(i)) => &objects[i],
185163
(2.., Some(_)) => bail!(
186164
"Multiple instances of {} were found, try specifying a unit",
187165
symbol_name
@@ -190,14 +168,13 @@ pub fn run(args: Args) -> Result<()> {
190168
}
191169
} else {
192170
bail!("Must specify one of: symbol, project and unit, target and base objects")
193-
}
194-
};
195-
let target_path = object.target_path.clone();
196-
let base_path = object.base_path.clone();
197-
(target_path, base_path, Some(project_config))
198-
}
199-
_ => bail!("Either target and base or project and unit must be specified"),
200-
};
171+
};
172+
let target_path = object.target_path.clone();
173+
let base_path = object.base_path.clone();
174+
(target_path, base_path, Some(project_config))
175+
}
176+
_ => bail!("Either target and base or project and unit must be specified"),
177+
};
201178

202179
if let Some(output) = &args.output {
203180
run_oneshot(&args, output, target_path.as_deref(), base_path.as_deref())
@@ -245,20 +222,20 @@ fn build_config_from_args(args: &Args) -> Result<(DiffObjConfig, MappingConfig)>
245222

246223
fn run_oneshot(
247224
args: &Args,
248-
output: &Path,
249-
target_path: Option<&Path>,
250-
base_path: Option<&Path>,
225+
output: &Utf8PlatformPath,
226+
target_path: Option<&Utf8PlatformPath>,
227+
base_path: Option<&Utf8PlatformPath>,
251228
) -> Result<()> {
252229
let output_format = OutputFormat::from_option(args.format.as_deref())?;
253230
let (diff_config, mapping_config) = build_config_from_args(args)?;
254231
let target = target_path
255232
.map(|p| {
256-
obj::read::read(p, &diff_config).with_context(|| format!("Loading {}", p.display()))
233+
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
257234
})
258235
.transpose()?;
259236
let base = base_path
260237
.map(|p| {
261-
obj::read::read(p, &diff_config).with_context(|| format!("Loading {}", p.display()))
238+
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
262239
})
263240
.transpose()?;
264241
let result =
@@ -272,10 +249,10 @@ fn run_oneshot(
272249
pub struct AppState {
273250
pub jobs: JobQueue,
274251
pub waker: Arc<TermWaker>,
275-
pub project_dir: Option<PathBuf>,
252+
pub project_dir: Option<Utf8PlatformPathBuf>,
276253
pub project_config: Option<ProjectConfig>,
277-
pub target_path: Option<PathBuf>,
278-
pub base_path: Option<PathBuf>,
254+
pub target_path: Option<Utf8PlatformPathBuf>,
255+
pub base_path: Option<Utf8PlatformPathBuf>,
279256
pub left_obj: Option<(ObjInfo, ObjDiff)>,
280257
pub right_obj: Option<(ObjInfo, ObjDiff)>,
281258
pub prev_obj: Option<(ObjInfo, ObjDiff)>,
@@ -315,6 +292,53 @@ fn create_objdiff_config(state: &AppState) -> ObjDiffConfig {
315292
}
316293
}
317294

295+
/// The configuration for a single object file.
296+
#[derive(Default, Clone, serde::Deserialize, serde::Serialize)]
297+
pub struct ObjectConfig {
298+
pub name: String,
299+
#[serde(default, with = "platform_path_serde_option")]
300+
pub target_path: Option<Utf8PlatformPathBuf>,
301+
#[serde(default, with = "platform_path_serde_option")]
302+
pub base_path: Option<Utf8PlatformPathBuf>,
303+
pub metadata: ProjectObjectMetadata,
304+
pub complete: Option<bool>,
305+
}
306+
307+
impl ObjectConfig {
308+
pub fn new(
309+
object: &ProjectObject,
310+
project_dir: &Utf8PlatformPath,
311+
target_obj_dir: Option<&Utf8PlatformPath>,
312+
base_obj_dir: Option<&Utf8PlatformPath>,
313+
) -> Self {
314+
let target_path = if let (Some(target_obj_dir), Some(path), None) =
315+
(target_obj_dir, &object.path, &object.target_path)
316+
{
317+
Some(target_obj_dir.join(path.with_platform_encoding()))
318+
} else if let Some(path) = &object.target_path {
319+
Some(project_dir.join(path.with_platform_encoding()))
320+
} else {
321+
None
322+
};
323+
let base_path = if let (Some(base_obj_dir), Some(path), None) =
324+
(base_obj_dir, &object.path, &object.base_path)
325+
{
326+
Some(base_obj_dir.join(path.with_platform_encoding()))
327+
} else if let Some(path) = &object.base_path {
328+
Some(project_dir.join(path.with_platform_encoding()))
329+
} else {
330+
None
331+
};
332+
Self {
333+
name: object.name().to_string(),
334+
target_path,
335+
base_path,
336+
metadata: object.metadata.clone().unwrap_or_default(),
337+
complete: object.complete(),
338+
}
339+
}
340+
}
341+
318342
impl AppState {
319343
fn reload(&mut self) -> Result<()> {
320344
let config = create_objdiff_config(self);
@@ -355,8 +379,8 @@ impl Wake for TermWaker {
355379

356380
fn run_interactive(
357381
args: Args,
358-
target_path: Option<PathBuf>,
359-
base_path: Option<PathBuf>,
382+
target_path: Option<Utf8PlatformPathBuf>,
383+
base_path: Option<Utf8PlatformPathBuf>,
360384
project_config: Option<ProjectConfig>,
361385
) -> Result<()> {
362386
let Some(symbol_name) = &args.symbol else { bail!("Interactive mode requires a symbol name") };
@@ -384,7 +408,7 @@ fn run_interactive(
384408
let watch_patterns = project_config.build_watch_patterns()?;
385409
state.watcher = Some(create_watcher(
386410
state.modified.clone(),
387-
project_dir,
411+
project_dir.as_ref(),
388412
build_globset(&watch_patterns)?,
389413
Waker::from(state.waker.clone()),
390414
)?);

0 commit comments

Comments
 (0)