feat: internal code dependency DAG visualization
This commit is contained in:
parent
85c7c557ee
commit
5311558643
8 changed files with 1830 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
/target
|
||||
tools/depgraph/target/
|
||||
node_modules/
|
||||
.vscode/
|
||||
.venv
|
||||
215
deps.dot
Normal file
215
deps.dot
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
digraph swactor {
|
||||
rankdir=LR;
|
||||
fontname="Helvetica";
|
||||
fontsize=14;
|
||||
node [fontname="Helvetica", fontsize=11, style=filled, shape=record];
|
||||
edge [fontname="Helvetica", fontsize=9];
|
||||
label="swactor — internal dependency DAG";
|
||||
labelloc=t;
|
||||
compound=true;
|
||||
newrank=true;
|
||||
splines=ortho;
|
||||
|
||||
subgraph cluster_error {
|
||||
label="error";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
Error [label="{Error|0: Box\<dyn std :: error :: Error + Send + Sync + 'static\>}", fillcolor="#e8f5e9"];
|
||||
}
|
||||
subgraph cluster_config {
|
||||
label="config";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
BackoffPolicy [label="{BackoffPolicy|spin_threshold: u32\nyield_threshold: u32\nsleep_increment_us: u64\nsleep_max_us: u64}", fillcolor="#e8f5e9"];
|
||||
RuntimeConfig [label="{RuntimeConfig|max_actors: usize\nactor_max_messages: usize\nnum_threads: usize\nmailbox_waterlevel: usize\nbackoff_policy: BackoffPolicy}", fillcolor="#e8f5e9"];
|
||||
}
|
||||
subgraph cluster_channel {
|
||||
label="channel";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
HybridChannel [label="{HybridChannel|ring: ArrayQueue\<T\>\noverflow: SegQueue\<T\>}", fillcolor="#fff9c4"];
|
||||
Receiver [label="{Receiver|queue: Arc\<HybridChannel\<T\>\>}", fillcolor="#fff9c4"];
|
||||
Sender [label="{Sender|queue: Arc\<HybridChannel\<T\>\>}", fillcolor="#fff9c4"];
|
||||
}
|
||||
subgraph cluster_actor {
|
||||
label="actor";
|
||||
style="rounded,filled"; fillcolor="#e3f2fd"; color="#1565c0";
|
||||
Message [label="{«trait» Message}", fillcolor="#bbdefb"];
|
||||
ActorInterface [label="{«trait» ActorInterface|Incoming(Message)\nResponse(Message)\nhandle((&self, &Ctx, Self::Incoming))}", fillcolor="#bbdefb"];
|
||||
ActorAddress [label="{ActorAddress|0: [u8; ..]}", fillcolor="#bbdefb"];
|
||||
Actor [label="{Actor|addr: ActorAddress\nmailbox: Mailbox\<A::Incoming\>\ninner: A}", fillcolor="#bbdefb"];
|
||||
AnyActor [label="{«trait» AnyActor|tick((&self, &dyn ContextInner) → bool)\ndeliver((&self, Box\<dyn Any + Send\>) → bool)}", fillcolor="#bbdefb"];
|
||||
}
|
||||
subgraph cluster_address_map {
|
||||
label="address_map";
|
||||
style="rounded,filled"; fillcolor="#f3e5f5"; color="#7b1fa2";
|
||||
WorkerId [label="{WorkerId|0: usize}", fillcolor="#e1bee7"];
|
||||
AddressMap [label="{AddressMap|inner: RwLock\<HashMap\<ActorAddress, WorkerId\>\>}", fillcolor="#e1bee7"];
|
||||
Placement [label="{Placement|next: AtomicUsize\nnum_workers: usize}", fillcolor="#e1bee7"];
|
||||
}
|
||||
subgraph cluster_runtime {
|
||||
label="runtime";
|
||||
style="rounded,filled"; fillcolor="#fce4ec"; color="#c62828";
|
||||
Inbox [label="{Inbox|addr: ActorAddress\ninner: Receiver\<M\>}", fillcolor="#ffcdd2"];
|
||||
RuntimeHandle [label="{RuntimeHandle|runtime: Arc\<Runtime\>\nthreads: Vec\<JoinHandle\<()\>\>}", fillcolor="#ffcdd2"];
|
||||
Ctx [label="{Ctx|inner: &'a dyn ContextInner\nself_addr: ActorAddress}", fillcolor="#ffcdd2"];
|
||||
SenderT [label="{«trait» SenderT|try_send_any((&self, Box\<dyn Any + Send\>))}", fillcolor="#ffcdd2"];
|
||||
Runtime [label="{Runtime|config: RuntimeConfig\naddress_map: Arc\<AddressMap\>\ninbox_registry: Arc\<InboxRegistry\>\ntransfer_txs: Vec\<Sender\<Envelope\>\>\nspawn_txs: Vec\<Sender\<(ActorAddress, Box\<dyn AnyActor\>)\>\>\nplacement: Placement\nis_running: AtomicBool\nsingle_worker: Option\<RefCell\<Worker\>\>\npending_workers: Option\<Vec\<Worker\>\>}", fillcolor="#ffcdd2"];
|
||||
Envelope [label="{Envelope|dest: ActorAddress\npayload: Box\<dyn Any + Send\>}", fillcolor="#ffcdd2"];
|
||||
InboxRegistry [label="{InboxRegistry|senders: RwLock\<HashMap\<ActorAddress, Arc\<dyn SenderT\>\>\>}", fillcolor="#ffcdd2"];
|
||||
ContextInner [label="{«trait» ContextInner|send_any((&self, ActorAddress, Box\<dyn Any + Send\>) → Result\<(), Error\>)\nspawn_any((&self, ActorAddress, Box\<dyn AnyActor\>) → Result\<(), Error\>)\nmailbox_waterlevel((&self) → usize)}", fillcolor="#ffcdd2"];
|
||||
}
|
||||
subgraph cluster_worker {
|
||||
label="worker";
|
||||
style="rounded,filled"; fillcolor="#fff3e0"; color="#e65100";
|
||||
TickContext [label="{TickContext|address_map: &'a AddressMap\ntransfer_txs: &'a [Sender\<Envelope\>]\nspawn_txs: &'a [Sender\<(ActorAddress, Box\<dyn AnyActor\>)\>]\nplacement: &'a Placement\ninbox_registry: &'a InboxRegistry\nconfig: &'a RuntimeConfig}", fillcolor="#ffe0b2"];
|
||||
Worker [label="{Worker|id: WorkerId\npool: ActorPool\ntransfer_rx: Receiver\<Envelope\>\nspawn_rx: Receiver\<(ActorAddress, Box\<dyn AnyActor\>)\>}", fillcolor="#ffe0b2"];
|
||||
WorkerContext [label="{WorkerContext|worker_id: WorkerId\naddress_map: &'a AddressMap\ntransfer_txs: &'a [Sender\<Envelope\>]\nspawn_txs: &'a [Sender\<(ActorAddress, Box\<dyn AnyActor\>)\>]\nplacement: &'a Placement\ninbox_registry: &'a InboxRegistry\nconfig: &'a RuntimeConfig\npending_local: &'a RefCell\<Vec\<(ActorAddress, Box\<dyn Any + Send\>)\>\>}", fillcolor="#ffe0b2"];
|
||||
ActorPool [label="{ActorPool|actors: HashMap\<ActorAddress, Box\<dyn AnyActor\>\>}", fillcolor="#ffe0b2"];
|
||||
Mailbox [label="{Mailbox|queue: VecDeque\<M\>\nwaterlevel: usize}", fillcolor="#ffe0b2"];
|
||||
}
|
||||
subgraph cluster_python {
|
||||
label="python (feature-gated)";
|
||||
style="rounded,dashed,filled"; fillcolor="#f5f5f5"; color="#999";
|
||||
PyMsg [label="{PyMsg|0: PyObject}", fillcolor="#d7ccc8"];
|
||||
PyActorAddress [label="{PyActorAddress|inner: ActorAddress}", fillcolor="#d7ccc8"];
|
||||
Effect [label="{«enum» Effect|Send \{ addr: ActorAddress, msg: PyObject \}\nSpawn \{ addr: ActorAddress, handler: PyObject \}}", fillcolor="#d7ccc8"];
|
||||
PyCtx [label="{PyCtx|self_addr: ActorAddress\neffects: RefCell\<Vec\<Effect\>\>}", fillcolor="#d7ccc8"];
|
||||
PyActor [label="{PyActor|handler: PyObject}", fillcolor="#d7ccc8"];
|
||||
PyInbox [label="{PyInbox|inner: Inbox\<PyMsg\>}", fillcolor="#d7ccc8"];
|
||||
PyRuntimeConfig [label="{PyRuntimeConfig|num_threads: usize\nmax_actors: usize\nactor_max_messages: usize\nmailbox_waterlevel: usize\nspin_threshold: u32\nyield_threshold: u32\nsleep_increment_us: u64\nsleep_max_us: u64}", fillcolor="#d7ccc8"];
|
||||
PyRuntime [label="{PyRuntime|inner: Option\<Runtime\>}", fillcolor="#d7ccc8"];
|
||||
PyRuntimeHandle [label="{PyRuntimeHandle|inner: Option\<RuntimeHandle\>}", fillcolor="#d7ccc8"];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// INTRA-MODULE EDGES (within same cluster)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
ActorInterface -> Message [label="Incoming", style=dashed, color="#666", penwidth=1];
|
||||
Actor -> ActorAddress [label="addr", style=dashed, color="#666", penwidth=1];
|
||||
Actor -> AnyActor [label="impl", style=dotted, color="#666", penwidth=1];
|
||||
Worker -> ActorPool [label="pool", style=dashed, color="#666", penwidth=1];
|
||||
Worker -> TickContext [label="tick_once() param", style=dashed, color="#666", penwidth=1];
|
||||
Receiver -> HybridChannel [label="queue", style=dashed, color="#666", penwidth=1];
|
||||
Sender -> HybridChannel [label="queue", style=dashed, color="#666", penwidth=1];
|
||||
Receiver -> Sender [label="new_sender() param", style=dashed, color="#666", penwidth=1];
|
||||
AddressMap -> WorkerId [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
Placement -> WorkerId [label="next_worker() param", style=dashed, color="#666", penwidth=1];
|
||||
RuntimeConfig -> BackoffPolicy [label="backoff_policy", style=dashed, color="#666", penwidth=1];
|
||||
RuntimeHandle -> Runtime [label="runtime", style=dashed, color="#666", penwidth=1];
|
||||
Ctx -> ContextInner [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> InboxRegistry [label="inbox_registry", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> Envelope [label="transfer_txs", style=dashed, color="#666", penwidth=1];
|
||||
InboxRegistry -> SenderT [label="senders", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> Inbox [label="new_inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> RuntimeHandle [label="run() param", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> ContextInner [label="impl", style=dotted, color="#666", penwidth=1];
|
||||
PyCtx -> Effect [label="effects", style=dashed, color="#666", penwidth=1];
|
||||
PyInbox -> PyMsg [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
PyCtx -> PyActorAddress [label="self_addr() param", style=dashed, color="#666", penwidth=1];
|
||||
PyInbox -> PyActorAddress [label="addr() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyRuntimeConfig [label="new() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyActorAddress [label="spawn() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyInbox [label="inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyRuntimeHandle [label="run() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntimeHandle -> PyActorAddress [label="spawn() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntimeHandle -> PyInbox [label="inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CROSS-MODULE EDGES (the real dependency DAG)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
// --- channel depends on runtime ---
|
||||
Sender -> SenderT [label="impl", style=dotted, color="#666", penwidth=1.5];
|
||||
|
||||
// --- actor depends on runtime ---
|
||||
ActorInterface -> Ctx [label="handle", style=solid, color="#1565c0", penwidth=1.5];
|
||||
AnyActor -> ContextInner [label="tick", style=solid, color="#1565c0", penwidth=1.5];
|
||||
Actor -> ContextInner [label="tick() param", style=solid, color="#1565c0", penwidth=1.5];
|
||||
|
||||
// --- actor depends on worker ---
|
||||
Actor -> Mailbox [label="mailbox", style=solid, color="#1565c0", penwidth=1.5];
|
||||
|
||||
// --- address_map depends on actor ---
|
||||
AddressMap -> ActorAddress [label="inner", style=solid, color="#7b1fa2", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on error ---
|
||||
ContextInner -> Error [label="send_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
Ctx -> Error [label="send() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Error [label="spawn() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
InboxRegistry -> Error [label="try_deliver() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on config ---
|
||||
Runtime -> RuntimeConfig [label="config", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on channel ---
|
||||
Inbox -> Receiver [label="inner", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Sender [label="transfer_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on actor ---
|
||||
Inbox -> ActorAddress [label="addr", style=solid, color="#c62828", penwidth=1.5];
|
||||
Ctx -> ActorAddress [label="self_addr", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> ActorAddress [label="spawn_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> AnyActor [label="spawn_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
Envelope -> ActorAddress [label="dest", style=solid, color="#c62828", penwidth=1.5];
|
||||
InboxRegistry -> ActorAddress [label="senders", style=solid, color="#c62828", penwidth=1.5];
|
||||
ContextInner -> ActorAddress [label="send_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
ContextInner -> AnyActor [label="spawn_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on address_map ---
|
||||
Runtime -> AddressMap [label="address_map", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Placement [label="placement", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on worker ---
|
||||
Runtime -> Worker [label="single_worker", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- worker depends on error ---
|
||||
WorkerContext -> Error [label="send_any() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on config ---
|
||||
TickContext -> RuntimeConfig [label="config", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> RuntimeConfig [label="config", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> BackoffPolicy [label="run() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on channel ---
|
||||
TickContext -> Sender [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> Receiver [label="transfer_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Sender [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on actor ---
|
||||
TickContext -> ActorAddress [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> AnyActor [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> ActorAddress [label="spawn_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> AnyActor [label="spawn_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> ActorAddress [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> AnyActor [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> ActorAddress [label="actors", style=solid, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> AnyActor [label="actors", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on address_map ---
|
||||
TickContext -> AddressMap [label="address_map", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> Placement [label="placement", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> WorkerId [label="id", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> WorkerId [label="worker_id", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> AddressMap [label="address_map", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Placement [label="placement", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on runtime ---
|
||||
TickContext -> Envelope [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> InboxRegistry [label="inbox_registry", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> Envelope [label="transfer_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Envelope [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> InboxRegistry [label="inbox_registry", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> ContextInner [label="impl", style=dotted, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> ContextInner [label="tick_all() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- python depends on actor ---
|
||||
PyActorAddress -> ActorAddress [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
Effect -> ActorAddress [label="Send", style=solid, color="#999", penwidth=1.5];
|
||||
PyCtx -> ActorAddress [label="self_addr", style=solid, color="#999", penwidth=1.5];
|
||||
PyActor -> ActorInterface [label="impl", style=dotted, color="#999", penwidth=1.5];
|
||||
|
||||
// --- python depends on runtime ---
|
||||
PyInbox -> Inbox [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyRuntime -> Runtime [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyRuntimeHandle -> RuntimeHandle [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyActor -> Ctx [label="handle() param", style=solid, color="#999", penwidth=1.5];
|
||||
}
|
||||
286
deps.html
Normal file
286
deps.html
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset='utf-8'>
|
||||
<title>swactor dependency DAG</title>
|
||||
<style>
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
body { background:#1a1a2e; overflow:hidden; font-family:system-ui; }
|
||||
#controls { position:fixed; top:12px; left:12px; z-index:10;
|
||||
background:rgba(30,30,60,0.9); border-radius:8px; padding:12px;
|
||||
color:#ccc; font-size:13px; backdrop-filter:blur(8px); }
|
||||
#controls button { background:#333; color:#fff; border:1px solid #555;
|
||||
border-radius:4px; padding:4px 10px; cursor:pointer; margin:0 3px; }
|
||||
#controls button:hover { background:#555; }
|
||||
#viewport { width:100vw; height:100vh; cursor:grab; }
|
||||
#viewport:active { cursor:grabbing; }
|
||||
#loading { position:fixed; top:50%; left:50%; transform:translate(-50%,-50%);
|
||||
color:#ccc; font-size:18px; }
|
||||
svg { display:block; }
|
||||
</style>
|
||||
</head><body>
|
||||
<div id='controls'>
|
||||
<strong>swactor dep graph</strong>
|
||||
<button onclick='zoomIn()'>+</button>
|
||||
<button onclick='zoomOut()'>−</button>
|
||||
<button onclick='resetView()'>fit</button>
|
||||
<span style='margin-left:8px;opacity:0.6'>scroll to zoom · drag to pan</span>
|
||||
</div>
|
||||
<div id='viewport'></div>
|
||||
<div id='loading'>Loading Graphviz…</div>
|
||||
<script type="module">
|
||||
import { instance } from 'https://cdn.jsdelivr.net/npm/@viz-js/viz@3.11.0/lib/viz-standalone.mjs';
|
||||
|
||||
const dot = `digraph swactor {
|
||||
rankdir=LR;
|
||||
fontname="Helvetica";
|
||||
fontsize=14;
|
||||
node [fontname="Helvetica", fontsize=11, style=filled, shape=record];
|
||||
edge [fontname="Helvetica", fontsize=9];
|
||||
label="swactor — internal dependency DAG";
|
||||
labelloc=t;
|
||||
compound=true;
|
||||
newrank=true;
|
||||
splines=ortho;
|
||||
|
||||
subgraph cluster_error {
|
||||
label="error";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
Error [label="{Error|0: Box\\<dyn std :: error :: Error + Send + Sync + 'static\\>}", fillcolor="#e8f5e9"];
|
||||
}
|
||||
subgraph cluster_config {
|
||||
label="config";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
BackoffPolicy [label="{BackoffPolicy|spin_threshold: u32\\nyield_threshold: u32\\nsleep_increment_us: u64\\nsleep_max_us: u64}", fillcolor="#e8f5e9"];
|
||||
RuntimeConfig [label="{RuntimeConfig|max_actors: usize\\nactor_max_messages: usize\\nnum_threads: usize\\nmailbox_waterlevel: usize\\nbackoff_policy: BackoffPolicy}", fillcolor="#e8f5e9"];
|
||||
}
|
||||
subgraph cluster_channel {
|
||||
label="channel";
|
||||
style="rounded,filled"; fillcolor="#f0f0f0"; color="#888";
|
||||
HybridChannel [label="{HybridChannel|ring: ArrayQueue\\<T\\>\\noverflow: SegQueue\\<T\\>}", fillcolor="#fff9c4"];
|
||||
Receiver [label="{Receiver|queue: Arc\\<HybridChannel\\<T\\>\\>}", fillcolor="#fff9c4"];
|
||||
Sender [label="{Sender|queue: Arc\\<HybridChannel\\<T\\>\\>}", fillcolor="#fff9c4"];
|
||||
}
|
||||
subgraph cluster_actor {
|
||||
label="actor";
|
||||
style="rounded,filled"; fillcolor="#e3f2fd"; color="#1565c0";
|
||||
Message [label="{«trait» Message}", fillcolor="#bbdefb"];
|
||||
ActorInterface [label="{«trait» ActorInterface|Incoming(Message)\\nResponse(Message)\\nhandle((&self, &Ctx, Self::Incoming))}", fillcolor="#bbdefb"];
|
||||
ActorAddress [label="{ActorAddress|0: [u8; ..]}", fillcolor="#bbdefb"];
|
||||
Actor [label="{Actor|addr: ActorAddress\\nmailbox: Mailbox\\<A::Incoming\\>\\ninner: A}", fillcolor="#bbdefb"];
|
||||
AnyActor [label="{«trait» AnyActor|tick((&self, &dyn ContextInner) → bool)\\ndeliver((&self, Box\\<dyn Any + Send\\>) → bool)}", fillcolor="#bbdefb"];
|
||||
}
|
||||
subgraph cluster_address_map {
|
||||
label="address_map";
|
||||
style="rounded,filled"; fillcolor="#f3e5f5"; color="#7b1fa2";
|
||||
WorkerId [label="{WorkerId|0: usize}", fillcolor="#e1bee7"];
|
||||
AddressMap [label="{AddressMap|inner: RwLock\\<HashMap\\<ActorAddress, WorkerId\\>\\>}", fillcolor="#e1bee7"];
|
||||
Placement [label="{Placement|next: AtomicUsize\\nnum_workers: usize}", fillcolor="#e1bee7"];
|
||||
}
|
||||
subgraph cluster_runtime {
|
||||
label="runtime";
|
||||
style="rounded,filled"; fillcolor="#fce4ec"; color="#c62828";
|
||||
Inbox [label="{Inbox|addr: ActorAddress\\ninner: Receiver\\<M\\>}", fillcolor="#ffcdd2"];
|
||||
RuntimeHandle [label="{RuntimeHandle|runtime: Arc\\<Runtime\\>\\nthreads: Vec\\<JoinHandle\\<()\\>\\>}", fillcolor="#ffcdd2"];
|
||||
Ctx [label="{Ctx|inner: &'a dyn ContextInner\\nself_addr: ActorAddress}", fillcolor="#ffcdd2"];
|
||||
SenderT [label="{«trait» SenderT|try_send_any((&self, Box\\<dyn Any + Send\\>))}", fillcolor="#ffcdd2"];
|
||||
Runtime [label="{Runtime|config: RuntimeConfig\\naddress_map: Arc\\<AddressMap\\>\\ninbox_registry: Arc\\<InboxRegistry\\>\\ntransfer_txs: Vec\\<Sender\\<Envelope\\>\\>\\nspawn_txs: Vec\\<Sender\\<(ActorAddress, Box\\<dyn AnyActor\\>)\\>\\>\\nplacement: Placement\\nis_running: AtomicBool\\nsingle_worker: Option\\<RefCell\\<Worker\\>\\>\\npending_workers: Option\\<Vec\\<Worker\\>\\>}", fillcolor="#ffcdd2"];
|
||||
Envelope [label="{Envelope|dest: ActorAddress\\npayload: Box\\<dyn Any + Send\\>}", fillcolor="#ffcdd2"];
|
||||
InboxRegistry [label="{InboxRegistry|senders: RwLock\\<HashMap\\<ActorAddress, Arc\\<dyn SenderT\\>\\>\\>}", fillcolor="#ffcdd2"];
|
||||
ContextInner [label="{«trait» ContextInner|send_any((&self, ActorAddress, Box\\<dyn Any + Send\\>) → Result\\<(), Error\\>)\\nspawn_any((&self, ActorAddress, Box\\<dyn AnyActor\\>) → Result\\<(), Error\\>)\\nmailbox_waterlevel((&self) → usize)}", fillcolor="#ffcdd2"];
|
||||
}
|
||||
subgraph cluster_worker {
|
||||
label="worker";
|
||||
style="rounded,filled"; fillcolor="#fff3e0"; color="#e65100";
|
||||
TickContext [label="{TickContext|address_map: &'a AddressMap\\ntransfer_txs: &'a [Sender\\<Envelope\\>]\\nspawn_txs: &'a [Sender\\<(ActorAddress, Box\\<dyn AnyActor\\>)\\>]\\nplacement: &'a Placement\\ninbox_registry: &'a InboxRegistry\\nconfig: &'a RuntimeConfig}", fillcolor="#ffe0b2"];
|
||||
Worker [label="{Worker|id: WorkerId\\npool: ActorPool\\ntransfer_rx: Receiver\\<Envelope\\>\\nspawn_rx: Receiver\\<(ActorAddress, Box\\<dyn AnyActor\\>)\\>}", fillcolor="#ffe0b2"];
|
||||
WorkerContext [label="{WorkerContext|worker_id: WorkerId\\naddress_map: &'a AddressMap\\ntransfer_txs: &'a [Sender\\<Envelope\\>]\\nspawn_txs: &'a [Sender\\<(ActorAddress, Box\\<dyn AnyActor\\>)\\>]\\nplacement: &'a Placement\\ninbox_registry: &'a InboxRegistry\\nconfig: &'a RuntimeConfig\\npending_local: &'a RefCell\\<Vec\\<(ActorAddress, Box\\<dyn Any + Send\\>)\\>\\>}", fillcolor="#ffe0b2"];
|
||||
ActorPool [label="{ActorPool|actors: HashMap\\<ActorAddress, Box\\<dyn AnyActor\\>\\>}", fillcolor="#ffe0b2"];
|
||||
Mailbox [label="{Mailbox|queue: VecDeque\\<M\\>\\nwaterlevel: usize}", fillcolor="#ffe0b2"];
|
||||
}
|
||||
subgraph cluster_python {
|
||||
label="python (feature-gated)";
|
||||
style="rounded,dashed,filled"; fillcolor="#f5f5f5"; color="#999";
|
||||
PyMsg [label="{PyMsg|0: PyObject}", fillcolor="#d7ccc8"];
|
||||
PyActorAddress [label="{PyActorAddress|inner: ActorAddress}", fillcolor="#d7ccc8"];
|
||||
Effect [label="{«enum» Effect|Send \\{ addr: ActorAddress, msg: PyObject \\}\\nSpawn \\{ addr: ActorAddress, handler: PyObject \\}}", fillcolor="#d7ccc8"];
|
||||
PyCtx [label="{PyCtx|self_addr: ActorAddress\\neffects: RefCell\\<Vec\\<Effect\\>\\>}", fillcolor="#d7ccc8"];
|
||||
PyActor [label="{PyActor|handler: PyObject}", fillcolor="#d7ccc8"];
|
||||
PyInbox [label="{PyInbox|inner: Inbox\\<PyMsg\\>}", fillcolor="#d7ccc8"];
|
||||
PyRuntimeConfig [label="{PyRuntimeConfig|num_threads: usize\\nmax_actors: usize\\nactor_max_messages: usize\\nmailbox_waterlevel: usize\\nspin_threshold: u32\\nyield_threshold: u32\\nsleep_increment_us: u64\\nsleep_max_us: u64}", fillcolor="#d7ccc8"];
|
||||
PyRuntime [label="{PyRuntime|inner: Option\\<Runtime\\>}", fillcolor="#d7ccc8"];
|
||||
PyRuntimeHandle [label="{PyRuntimeHandle|inner: Option\\<RuntimeHandle\\>}", fillcolor="#d7ccc8"];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// INTRA-MODULE EDGES (within same cluster)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
ActorInterface -> Message [label="Incoming", style=dashed, color="#666", penwidth=1];
|
||||
Actor -> ActorAddress [label="addr", style=dashed, color="#666", penwidth=1];
|
||||
Actor -> AnyActor [label="impl", style=dotted, color="#666", penwidth=1];
|
||||
Worker -> ActorPool [label="pool", style=dashed, color="#666", penwidth=1];
|
||||
Worker -> TickContext [label="tick_once() param", style=dashed, color="#666", penwidth=1];
|
||||
Receiver -> HybridChannel [label="queue", style=dashed, color="#666", penwidth=1];
|
||||
Sender -> HybridChannel [label="queue", style=dashed, color="#666", penwidth=1];
|
||||
Receiver -> Sender [label="new_sender() param", style=dashed, color="#666", penwidth=1];
|
||||
AddressMap -> WorkerId [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
Placement -> WorkerId [label="next_worker() param", style=dashed, color="#666", penwidth=1];
|
||||
RuntimeConfig -> BackoffPolicy [label="backoff_policy", style=dashed, color="#666", penwidth=1];
|
||||
RuntimeHandle -> Runtime [label="runtime", style=dashed, color="#666", penwidth=1];
|
||||
Ctx -> ContextInner [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> InboxRegistry [label="inbox_registry", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> Envelope [label="transfer_txs", style=dashed, color="#666", penwidth=1];
|
||||
InboxRegistry -> SenderT [label="senders", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> Inbox [label="new_inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> RuntimeHandle [label="run() param", style=dashed, color="#666", penwidth=1];
|
||||
Runtime -> ContextInner [label="impl", style=dotted, color="#666", penwidth=1];
|
||||
PyCtx -> Effect [label="effects", style=dashed, color="#666", penwidth=1];
|
||||
PyInbox -> PyMsg [label="inner", style=dashed, color="#666", penwidth=1];
|
||||
PyCtx -> PyActorAddress [label="self_addr() param", style=dashed, color="#666", penwidth=1];
|
||||
PyInbox -> PyActorAddress [label="addr() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyRuntimeConfig [label="new() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyActorAddress [label="spawn() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyInbox [label="inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntime -> PyRuntimeHandle [label="run() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntimeHandle -> PyActorAddress [label="spawn() param", style=dashed, color="#666", penwidth=1];
|
||||
PyRuntimeHandle -> PyInbox [label="inbox() param", style=dashed, color="#666", penwidth=1];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CROSS-MODULE EDGES (the real dependency DAG)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
// --- channel depends on runtime ---
|
||||
Sender -> SenderT [label="impl", style=dotted, color="#666", penwidth=1.5];
|
||||
|
||||
// --- actor depends on runtime ---
|
||||
ActorInterface -> Ctx [label="handle", style=solid, color="#1565c0", penwidth=1.5];
|
||||
AnyActor -> ContextInner [label="tick", style=solid, color="#1565c0", penwidth=1.5];
|
||||
Actor -> ContextInner [label="tick() param", style=solid, color="#1565c0", penwidth=1.5];
|
||||
|
||||
// --- actor depends on worker ---
|
||||
Actor -> Mailbox [label="mailbox", style=solid, color="#1565c0", penwidth=1.5];
|
||||
|
||||
// --- address_map depends on actor ---
|
||||
AddressMap -> ActorAddress [label="inner", style=solid, color="#7b1fa2", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on error ---
|
||||
ContextInner -> Error [label="send_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
Ctx -> Error [label="send() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Error [label="spawn() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
InboxRegistry -> Error [label="try_deliver() param", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on config ---
|
||||
Runtime -> RuntimeConfig [label="config", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on channel ---
|
||||
Inbox -> Receiver [label="inner", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Sender [label="transfer_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on actor ---
|
||||
Inbox -> ActorAddress [label="addr", style=solid, color="#c62828", penwidth=1.5];
|
||||
Ctx -> ActorAddress [label="self_addr", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> ActorAddress [label="spawn_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> AnyActor [label="spawn_txs", style=solid, color="#c62828", penwidth=1.5];
|
||||
Envelope -> ActorAddress [label="dest", style=solid, color="#c62828", penwidth=1.5];
|
||||
InboxRegistry -> ActorAddress [label="senders", style=solid, color="#c62828", penwidth=1.5];
|
||||
ContextInner -> ActorAddress [label="send_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
ContextInner -> AnyActor [label="spawn_any", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on address_map ---
|
||||
Runtime -> AddressMap [label="address_map", style=solid, color="#c62828", penwidth=1.5];
|
||||
Runtime -> Placement [label="placement", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- runtime depends on worker ---
|
||||
Runtime -> Worker [label="single_worker", style=solid, color="#c62828", penwidth=1.5];
|
||||
|
||||
// --- worker depends on error ---
|
||||
WorkerContext -> Error [label="send_any() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on config ---
|
||||
TickContext -> RuntimeConfig [label="config", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> RuntimeConfig [label="config", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> BackoffPolicy [label="run() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on channel ---
|
||||
TickContext -> Sender [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> Receiver [label="transfer_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Sender [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on actor ---
|
||||
TickContext -> ActorAddress [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> AnyActor [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> ActorAddress [label="spawn_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> AnyActor [label="spawn_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> ActorAddress [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> AnyActor [label="spawn_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> ActorAddress [label="actors", style=solid, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> AnyActor [label="actors", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on address_map ---
|
||||
TickContext -> AddressMap [label="address_map", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> Placement [label="placement", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> WorkerId [label="id", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> WorkerId [label="worker_id", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> AddressMap [label="address_map", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Placement [label="placement", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- worker depends on runtime ---
|
||||
TickContext -> Envelope [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
TickContext -> InboxRegistry [label="inbox_registry", style=solid, color="#e65100", penwidth=1.5];
|
||||
Worker -> Envelope [label="transfer_rx", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> Envelope [label="transfer_txs", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> InboxRegistry [label="inbox_registry", style=solid, color="#e65100", penwidth=1.5];
|
||||
WorkerContext -> ContextInner [label="impl", style=dotted, color="#e65100", penwidth=1.5];
|
||||
ActorPool -> ContextInner [label="tick_all() param", style=solid, color="#e65100", penwidth=1.5];
|
||||
|
||||
// --- python depends on actor ---
|
||||
PyActorAddress -> ActorAddress [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
Effect -> ActorAddress [label="Send", style=solid, color="#999", penwidth=1.5];
|
||||
PyCtx -> ActorAddress [label="self_addr", style=solid, color="#999", penwidth=1.5];
|
||||
PyActor -> ActorInterface [label="impl", style=dotted, color="#999", penwidth=1.5];
|
||||
|
||||
// --- python depends on runtime ---
|
||||
PyInbox -> Inbox [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyRuntime -> Runtime [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyRuntimeHandle -> RuntimeHandle [label="inner", style=solid, color="#999", penwidth=1.5];
|
||||
PyActor -> Ctx [label="handle() param", style=solid, color="#999", penwidth=1.5];
|
||||
}
|
||||
`;
|
||||
|
||||
const viz = await instance();
|
||||
const svg = viz.renderSVGElement(dot);
|
||||
document.getElementById('loading').remove();
|
||||
|
||||
const vp = document.getElementById('viewport');
|
||||
vp.appendChild(svg);
|
||||
|
||||
// invert colors for dark mode
|
||||
svg.querySelectorAll('polygon[fill="white"]').forEach(el => el.setAttribute('fill','#1a1a2e'));
|
||||
|
||||
// Recolor text: node text stays dark (readable on light fills), everything else goes light
|
||||
svg.querySelectorAll('.graph > text, .cluster > text, .edge text').forEach(el => el.setAttribute('fill','#e0e0e0'));
|
||||
// Node text (inside record shapes): keep dark for readability on pastel fills
|
||||
svg.querySelectorAll('.node text').forEach(el => el.setAttribute('fill','#1a1a1a'));
|
||||
|
||||
// pan & zoom
|
||||
let scale = 1, tx = 0, ty = 0, dragging = false, sx = 0, sy = 0;
|
||||
function applyTransform() { svg.style.transform = `translate(${tx}px,${ty}px) scale(${scale})`; svg.style.transformOrigin = '0 0'; }
|
||||
function resetView() {
|
||||
const vw = window.innerWidth, vh = window.innerHeight;
|
||||
const bb = svg.getBBox();
|
||||
scale = Math.min(vw / bb.width, vh / bb.height) * 0.92;
|
||||
tx = (vw - bb.width * scale) / 2;
|
||||
ty = (vh - bb.height * scale) / 2;
|
||||
applyTransform();
|
||||
}
|
||||
resetView();
|
||||
|
||||
vp.addEventListener('wheel', e => { e.preventDefault(); const f = e.deltaY < 0 ? 1.12 : 0.89; const rect = vp.getBoundingClientRect(); const mx = e.clientX - rect.left; const my = e.clientY - rect.top; tx = mx - f * (mx - tx); ty = my - f * (my - ty); scale *= f; applyTransform(); }, { passive:false });
|
||||
vp.addEventListener('pointerdown', e => { dragging=true; sx=e.clientX-tx; sy=e.clientY-ty; vp.setPointerCapture(e.pointerId); });
|
||||
vp.addEventListener('pointermove', e => { if(!dragging) return; tx=e.clientX-sx; ty=e.clientY-sy; applyTransform(); });
|
||||
vp.addEventListener('pointerup', () => dragging=false);
|
||||
|
||||
function zoomIn() { scale*=1.3; applyTransform(); }
|
||||
function zoomOut() { scale*=0.7; applyTransform(); }
|
||||
</script>
|
||||
</body></html>
|
||||
18
package-lock.json
generated
Normal file
18
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "workspace",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@viz-js/viz": "^3.24.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@viz-js/viz": {
|
||||
"version": "3.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@viz-js/viz/-/viz-3.24.0.tgz",
|
||||
"integrity": "sha512-sTRz2cFN6PwICVC7GVlF2aYNAZ/LwF7Y1mp3B+8LXQ7otyHrzQYSzNBwJ4lctL/aS3x97ppw59z6zIW+wPs6bQ==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
package.json
Normal file
5
package.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@viz-js/viz": "^3.24.0"
|
||||
}
|
||||
}
|
||||
46
tools/depgraph/Cargo.lock
generated
Normal file
46
tools/depgraph/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "depgraph"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
8
tools/depgraph/Cargo.toml
Normal file
8
tools/depgraph/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "depgraph"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2", features = ["full", "visit"] }
|
||||
quote = "1"
|
||||
1250
tools/depgraph/src/main.rs
Normal file
1250
tools/depgraph/src/main.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue