Skip to main content

qcode/value/util/
base_ref.rs

1// TODO: maybe try to reuse some of num_ref's code here?
2
3use crate::{
4    context::{Context, Shared},
5    value::ValueId,
6};
7
8/// A generic wrapper struct for referencing an ID with a context.
9/// This is the basis for all `*Ref` and `*MutRef`.
10///
11/// `Id` is any cheap `Copy` handle — either a `Registry` `Identifier` (varnode,
12/// literal, function, …) or a composite IR id (`InstructionId`, `BlockId`, …).
13/// The bound is intentionally just `Copy`; routing to storage is the concern of
14/// the concrete ref impls, not this wrapper.
15pub struct BaseRef<Ctx, Id: Copy> {
16    pub id: Id,
17    pub(in crate::value) ctx: Ctx,
18}
19
20impl<Ctx, Id: Copy> BaseRef<Ctx, Id> {
21    pub fn new(ctx: Ctx, id: Id) -> Self {
22        BaseRef { id, ctx }
23    }
24}
25
26impl<Ctx, Id: Copy + Into<ValueId>> BaseRef<Ctx, Id> {
27    pub fn id(&self) -> ValueId {
28        self.id.into()
29    }
30}
31
32impl<'str, 'ctx, Id: Copy> BaseRef<&'ctx Context<'str>, Id> {
33    pub fn from_id(ctx: &'ctx Context<'str>, id: Id) -> Self {
34        BaseRef { id, ctx }
35    }
36}
37
38/// Construct a shared-leaf wrapper ref (literal, bytes, varnode) over the
39/// module's [`Shared`] IR state, taking **either** a `&Context` or a `&Shared`
40/// (via [`AsShared`]) so module- and pass-scope callers share one spelling
41/// (context-split stage 5b-ii item #1).
42impl<'a, 'str, Id: Copy> BaseRef<&'a Shared<'str>, Id> {
43    pub fn from_id(src: impl AsShared<'a, 'str>, id: Id) -> Self {
44        BaseRef {
45            id,
46            ctx: src.as_shared(),
47        }
48    }
49}
50
51impl<'str, 'ctx, Id: Copy> BaseRef<&'ctx mut Context<'str>, Id> {
52    pub fn from_id(ctx: &'ctx mut Context<'str>, id: Id) -> Self {
53        BaseRef { id, ctx }
54    }
55}
56
57/// Convert mutable refs to immutable refs by cloning the ID and sharing the context reference.
58impl<'str, 'ctx, Id: Copy> From<BaseRef<&'ctx mut Context<'str>, Id>>
59    for BaseRef<&'ctx Context<'str>, Id>
60{
61    fn from(r: BaseRef<&'ctx mut Context<'str>, Id>) -> Self {
62        BaseRef {
63            id: r.id,
64            ctx: r.ctx,
65        }
66    }
67}
68
69pub trait WithCtx<'s, 'ctx: 's, 'str: 'ctx> {
70    fn ctx(&'s self) -> &'ctx Context<'str>;
71}
72
73/// Narrows a module handle to its [`Shared`] IR state, so the shared-leaf
74/// wrapper-ref constructors (`Varnode::from_id`, `Space::from_id`,
75/// `LiteralRef`/`BytesRef`) accept **either** a whole `&Context` (module scope)
76/// **or** a bare `&Shared` (pass scope, via `QCodeView::shared()` /
77/// `BodyMut::shr()`) with no call-site churn (context-split stage 5b-ii item
78/// #1). The leaf refs themselves store only a `&Shared`.
79pub trait AsShared<'a, 'str> {
80    // Implemented only for `Copy` reference types (`&Context`, `&Shared`), so
81    // taking `self` by value is a cheap pointer copy, not an owning move.
82    #[allow(clippy::wrong_self_convention)]
83    fn as_shared(self) -> &'a Shared<'str>;
84}
85
86impl<'a, 'str> AsShared<'a, 'str> for &'a Shared<'str> {
87    fn as_shared(self) -> &'a Shared<'str> {
88        self
89    }
90}
91
92impl<'a, 'str> AsShared<'a, 'str> for &'a Context<'str> {
93    fn as_shared(self) -> &'a Shared<'str> {
94        &self.shared
95    }
96}
97
98/// The shared-leaf twin of [`WithCtx`]: a ref that can yield the module's
99/// [`Shared`] IR state (interners, spaces, registers, name map) for its read
100/// methods. Implemented by the shared-leaf wrapper refs (literal, bytes,
101/// varnode) — which now carry only a `&Shared` — and by their `&mut Context`
102/// mutation twins (which narrow through `self.ctx.shared`). This replaces the
103/// leaf refs' old `WithCtx` dependency: a shared-leaf value never needs the
104/// whole `&Context`, only its shared part (context-split stage 5b-ii item #1).
105pub trait WithShared<'s, 'sh: 's, 'str: 'sh> {
106    fn shared(&'s self) -> &'sh Shared<'str>;
107}
108
109pub trait WithCtxMut<'s, 'str: 's>: WithCtx<'s, 's, 'str> {
110    fn ctx_mut(&'s mut self) -> &'s mut Context<'str>;
111}