split_modules/model.rs
1//! Core data types shared across the split pipeline.
2
3use std::path::PathBuf;
4
5/// How the parent module owns its submodule files on disk.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Layout {
8 /// `foo.rs` → submodule files live in a sibling `foo/` directory.
9 Adjacent,
10 /// `lib.rs` / `main.rs` / `mod.rs` → submodule files live in the same directory.
11 DirOwner,
12}
13
14/// User-facing configuration for a split run.
15#[derive(Debug, Clone)]
16pub struct Config {
17 /// Run `cargo check` after splitting and roll back if it fails.
18 pub verify: bool,
19 /// Run `rustfmt` on generated/changed files when available.
20 pub rustfmt: bool,
21 /// Print the plan but do not touch the filesystem.
22 pub dry_run: bool,
23 /// In recursive mode, only split files that would yield at least this many module files.
24 pub min_groups: usize,
25}
26
27impl Default for Config {
28 fn default() -> Self {
29 Config {
30 verify: true,
31 rustfmt: true,
32 dry_run: false,
33 min_groups: 2,
34 }
35 }
36}
37
38/// How an item's visibility must be rewritten when it moves into a child module,
39/// so the parent can still re-export it at its original visibility.
40#[derive(Debug, Clone)]
41pub struct VisEdit {
42 /// Byte range *within the item's own source slice* to replace.
43 /// A zero-width range means "insert at this offset".
44 pub rel_start: usize,
45 pub rel_end: usize,
46 /// Replacement / inserted text (e.g. `pub(super) ` or `pub(crate)`).
47 pub text: String,
48}
49
50/// A re-export emitted in the parent module to preserve the original namespace.
51#[derive(Debug, Clone)]
52pub struct ReExport {
53 /// Visibility rendered exactly as the item originally declared it.
54 pub vis: String,
55 /// The item's identifier.
56 pub name: String,
57 /// `#[cfg(...)]` attributes to replicate onto the re-export, if any.
58 pub cfg_attrs: Vec<String>,
59}
60
61/// A single top-level item that will move into a child module file.
62#[derive(Debug, Clone)]
63pub struct MovedItem {
64 /// Target file stem (snake_case); items sharing a stem share a file.
65 pub group: String,
66 /// Plain `//` comment block immediately preceding the item (already-doc comments
67 /// are part of `text`). May be empty.
68 pub leading_comment: String,
69 /// Raw source slice of the item, including doc-comments and attributes.
70 pub text: String,
71 /// Visibility rewrites to apply to `text` for the child file (item + members).
72 pub vis_edits: Vec<VisEdit>,
73 /// Re-export to emit in the parent (None for `impl` blocks).
74 pub reexport: Option<ReExport>,
75 /// Original order index in the source file.
76 pub order: usize,
77}
78
79/// One generated child module file.
80#[derive(Debug, Clone)]
81pub struct GroupFile {
82 pub stem: String,
83 /// Indices into [`SplitPlan::moved`], in original source order.
84 pub item_indices: Vec<usize>,
85}
86
87/// The full plan for splitting one source file.
88#[derive(Debug, Clone)]
89pub struct SplitPlan {
90 pub source_path: PathBuf,
91 pub layout: Layout,
92 /// Directory where child files are written.
93 pub out_dir: PathBuf,
94 /// New parent file contents (the original file rewritten as a module index).
95 pub parent_contents: String,
96 /// Items being moved.
97 pub moved: Vec<MovedItem>,
98 /// Generated files (stem + which items).
99 pub files: Vec<GroupFile>,
100}
101
102impl SplitPlan {
103 /// Whether this plan actually changes anything.
104 pub fn is_noop(&self) -> bool {
105 self.files.len() < 2
106 }
107}
108
109/// Outcome of attempting to split one file.
110#[derive(Debug)]
111pub enum FileOutcome {
112 Split { files: Vec<PathBuf> },
113 Skipped(String),
114 RolledBack(String),
115}