• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adierking / unplug / 15940344048

28 Jun 2025 04:12AM UTC coverage: 77.613%. First build
15940344048

push

github

adierking
hsd: Vertex data

0 of 109 new or added lines in 6 files covered. (0.0%)

20344 of 26212 relevant lines covered (77.61%)

1089927.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/unplug/src/hsd/pointer.rs
1
use super::{Error, Result};
2
use crate::common::ReadFrom;
3
use bumpalo::Bump;
4
use std::cell::{Ref, RefCell, RefMut};
5
use std::io::Read;
6
use std::num::NonZeroU32;
7

8
// This is some convoluted type system stuff to support the node graph (yay, Rust!). Basically, a
9
// Pointer can either be null or hold a reference to a node. When we read a pointer, we need to put
10
// the offset in a queue where we also know what type of node to read there. Each pointer also has
11
// to be given a reference to the default-initialized node, because we don't want to have to deal
12
// with needing a reference to the entire archive every time you dereference a pointer. As the
13
// reader goes through the queue, it will eventually initialize each node.
14
//
15
// The tricky thing here is that to support reading each node based on its type, we have to use a
16
// dyn-compatible trait. So we split the node traits between NodeBase (which is dyn-compatible) and
17
// the public Node trait (which is a marker that ensures a type conforms to the correct traits). We
18
// also have to take a dyn pointer to the reader, and we want to be able to read generic node types,
19
// so we also split that between ReadPointerBase (dyn-compatible) and ReadPointer. This makes it
20
// super easy to write the ReadFrom impls for each node.
21
//
22
// All of the memory is stored in a Bump arena that gets dropped when we're done with the archive,
23
// otherwise managing lifetimes here would become insanely difficult. Currently, we also just put
24
// each node into a RefCell to make borrow checking easier.
25

26
pub trait ReadPointerBase<'a>: Read {
27
    /// Get the arena belonging to the node graph.
28
    fn arena(&self) -> &'a Bump;
29

30
    /// Read a 32-bit offset and validate that it has a relocation pointing to it.
31
    fn read_offset(&mut self) -> Result<Option<NonZeroU32>>;
32

33
    /// Enqueue a node to be read at an offset.
34
    fn add_node(&mut self, offset: u32, node: &'a RefCell<dyn NodeBase<'a>>);
35
}
36

37
pub trait NodeBase<'a>: 'a {
38
    /// Read the node's data from a reader. `max_size` is an upper bound on the known size of the object.
39
    fn read<'r>(&mut self, reader: &'r mut dyn ReadPointerBase<'a>, max_size: usize) -> Result<()>;
40
}
41

42
// Auto-implement NodeBase for anything which supports ReadFrom<ReadPointer>.
43
impl<'a, T: 'a> NodeBase<'a> for T
44
where
45
    for<'x> T: ReadFrom<dyn ReadPointerBase<'a> + 'x, Error = Error> + 'a,
46
{
NEW
47
    fn read<'r>(
×
NEW
48
        &mut self,
×
NEW
49
        reader: &'r mut dyn ReadPointerBase<'a>,
×
NEW
50
        _max_size: usize,
×
NEW
51
    ) -> Result<()> {
×
52
        *self = T::read_from(reader)?;
×
53
        Ok(())
×
54
    }
×
55
}
56

57
/// Trait for a value that can be default-initialized using an arena.
58
pub trait DefaultIn<'a> {
59
    fn default_in(arena: &'a Bump) -> Self;
60
}
61

62
impl<'a, T: Default> DefaultIn<'a> for T {
63
    fn default_in(_arena: &'a Bump) -> Self {
×
64
        Self::default()
×
65
    }
×
66
}
67

68
/// Marker trait which ensures that a type conforms to all of the necessary traits for a node.
69
/// Technically this is not necessary and we could use just NodeBase everywhere, but this makes it
70
/// more explicit which types are actually nodes.
71
pub trait Node<'a>: NodeBase<'a> {}
72

73
// () is a node with nothing in it. Useful for pointers to unimplemented structs.
74
impl Node<'_> for () {}
75
impl<'a, R: ReadPointer<'a> + ?Sized> ReadFrom<R> for () {
76
    type Error = Error;
77
    fn read_from(_reader: &mut R) -> Result<Self> {
×
78
        Ok(())
×
79
    }
×
80
}
81

82
/// Holds a nullable reference to a node in the graph.
83
#[derive(Copy, Clone, PartialEq, Eq)]
×
84
#[repr(transparent)]
85
pub struct Pointer<'a, T: Node<'a>>(Option<&'a RefCell<T>>);
86

87
impl<'a, T: Node<'a> + std::fmt::Debug> std::fmt::Debug for Pointer<'a, T> {
88
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
89
        match self.0 {
×
90
            Some(n) => f.debug_tuple("Pointer").field(&*n.borrow()).finish(),
×
91
            None => f.debug_tuple("Pointer").field(&self.0).finish(),
×
92
        }
93
    }
×
94
}
95

96
impl<'a, T: Node<'a>> Pointer<'a, T> {
97
    pub fn new() -> Self {
×
98
        Self(None)
×
99
    }
×
100

101
    pub fn alloc(arena: &'a Bump, node: T) -> Self {
×
102
        Self(Some(arena.alloc(RefCell::new(node))))
×
103
    }
×
104

105
    pub fn borrow(&self) -> Option<Ref<'a, T>> {
×
106
        self.0.map(|obj| obj.borrow())
×
107
    }
×
108

109
    pub fn borrow_mut(&self) -> Option<RefMut<'a, T>> {
×
110
        self.0.map(|obj| obj.borrow_mut())
×
111
    }
×
112

113
    pub fn is_null(&self) -> bool {
×
114
        self.0.is_none()
×
115
    }
×
116
}
117

118
impl<'a, T: Node<'a>> Default for Pointer<'a, T> {
119
    fn default() -> Self {
×
120
        Self::new()
×
121
    }
×
122
}
123

124
/// Extension trait for ReadPointerBase which provides the generic read_pointer().
125
pub trait ReadPointer<'a>: ReadPointerBase<'a> {
126
    /// Read a pointer from the stream with default-constructed node data.
NEW
127
    fn read_pointer<T: Node<'a> + DefaultIn<'a>>(&mut self) -> Result<Pointer<'a, T>> {
×
128
        self.read_pointer_into(T::default_in(self.arena()))
×
129
    }
×
130

131
    /// Read a pointer from the stream. The node data will be read into the given node object.
132
    fn read_pointer_into<T: Node<'a>>(&mut self, node: T) -> Result<Pointer<'a, T>> {
133
        match self.read_offset()? {
×
134
            Some(offset) => self.read_node(offset.get(), node),
×
135
            None => Ok(Pointer(None)),
×
136
        }
137
    }
×
138

139
    /// Read a node from the stream at the given offset and return a pointer for it.
140
    fn read_node<T: Node<'a>>(&mut self, offset: u32, node: T) -> Result<Pointer<'a, T>> {
×
141
        let pointer = Pointer::alloc(self.arena(), node);
×
142
        self.add_node(offset, pointer.0.unwrap());
×
143
        Ok(pointer)
×
144
    }
×
145
}
146

147
impl<'a, R: ReadPointerBase<'a> + ?Sized> ReadPointer<'a> for R {}
148

149
// Implement ReadFrom for pointers by delegating to read_pointer().
150
impl<'a, R, T> ReadFrom<R> for Pointer<'a, T>
151
where
152
    R: ReadPointer<'a> + ?Sized,
153
    T: Node<'a> + DefaultIn<'a>,
154
{
155
    type Error = Error;
NEW
156
    fn read_from(reader: &mut R) -> Result<Self> {
×
NEW
157
        reader.read_pointer()
×
NEW
158
    }
×
159
}
160

161
// Necessary for pointer arrays.
162
impl<'a, T: Node<'a> + DefaultIn<'a>> Node<'a> for Pointer<'a, T> {}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc