dusk_cdf/
source.rs

1use std::{io, mem};
2
3use crate::{
4    Config, DecodableElement, DecoderContext, Element, EncodableElement, EncoderContext, Preamble,
5};
6
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub(crate) struct EncodedSource {
9    pub(crate) line: u64,
10    pub(crate) col: u64,
11    pub(crate) contents_index: usize,
12}
13
14impl EncodedSource {
15    const fn new(line: u64, col: u64, contents_index: usize) -> Self {
16        Self {
17            line,
18            col,
19            contents_index,
20        }
21    }
22}
23
24impl Element for EncodedSource {
25    fn len(ctx: &Config) -> usize {
26        2 * u64::len(ctx) + usize::len(ctx)
27    }
28
29    fn validate(&self, preamble: &Preamble) -> io::Result<()> {
30        self.line.validate(preamble)?;
31        self.col.validate(preamble)?;
32        self.contents_index.validate(preamble)?;
33
34        Ok(())
35    }
36}
37
38impl EncodableElement for EncodedSource {
39    fn to_buffer(&self, ctx: &mut EncoderContext, buf: &mut [u8]) {
40        let buf = self.line.encode(ctx, buf);
41        let buf = self.col.encode(ctx, buf);
42        let _ = self.contents_index.encode(ctx, buf);
43    }
44}
45
46impl DecodableElement for EncodedSource {
47    fn try_from_buffer_in_place<'b>(
48        &mut self,
49        ctx: &DecoderContext,
50        buf: &'b [u8],
51    ) -> io::Result<()> {
52        Self::validate_buffer(ctx.config(), buf)?;
53
54        let buf = self.line.try_decode_in_place(ctx, buf)?;
55        let buf = self.col.try_decode_in_place(ctx, buf)?;
56        let _ = self.contents_index.try_decode_in_place(ctx, buf)?;
57
58        Ok(())
59    }
60}
61
62/// Source file tripler that can be encoded into a CDF file
63#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
64pub struct EncodableSource {
65    line: u64,
66    col: u64,
67    path: String,
68}
69
70impl EncodableSource {
71    /// Create a new source instance
72    pub const fn new(line: u64, col: u64, path: String) -> Self {
73        Self { line, col, path }
74    }
75
76    /// Source line
77    pub const fn line(&self) -> u64 {
78        self.line
79    }
80
81    /// Source column
82    pub const fn col(&self) -> u64 {
83        self.col
84    }
85
86    /// Path to be encoded
87    pub fn path(&self) -> &str {
88        &self.path
89    }
90}
91
92impl Element for EncodableSource {
93    fn len(ctx: &Config) -> usize {
94        EncodedSource::len(ctx)
95    }
96
97    fn validate(&self, preamble: &Preamble) -> io::Result<()> {
98        self.line.validate(preamble)?;
99        self.col.validate(preamble)?;
100
101        Ok(())
102    }
103}
104
105impl EncodableElement for EncodableSource {
106    fn to_buffer(&self, ctx: &mut EncoderContext, buf: &mut [u8]) {
107        let contents_index = ctx.add_path(self.path.clone());
108        let encodable = EncodedSource::new(self.line, self.col, contents_index);
109
110        encodable.to_buffer(ctx, buf)
111    }
112}
113
114/// Source file decoded from a CDF file
115#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct DecodedSource<'a> {
117    pub(crate) line: u64,
118    pub(crate) col: u64,
119    pub(crate) name: &'a str,
120    pub(crate) contents: &'a str,
121}
122
123impl<'a> Element for DecodedSource<'a> {
124    fn len(ctx: &Config) -> usize {
125        EncodedSource::len(ctx)
126    }
127
128    fn validate(&self, preamble: &Preamble) -> io::Result<()> {
129        self.line.validate(preamble)?;
130        self.col.validate(preamble)?;
131
132        Ok(())
133    }
134}
135
136impl<'a> DecodableElement for DecodedSource<'a> {
137    fn try_from_buffer_in_place<'x, 'b>(
138        &'x mut self,
139        ctx: &DecoderContext<'x>,
140        buf: &'b [u8],
141    ) -> io::Result<()> {
142        let (encoded, _) = EncodedSource::try_decode(ctx, buf)?;
143        let EncodedSource {
144            line,
145            col,
146            contents_index,
147        } = encoded;
148
149        let name = ctx.fetch_name(contents_index).ok_or_else(|| {
150            io::Error::new(
151                io::ErrorKind::Other,
152                "the source name wasn't available in the file cache",
153            )
154        })?;
155
156        let contents = ctx.fetch_contents(contents_index).ok_or_else(|| {
157            io::Error::new(
158                io::ErrorKind::Other,
159                "the source contents wasn't available in the file cache",
160            )
161        })?;
162
163        self.line = line;
164        self.col = col;
165
166        // the compiler isn't smart enough here to understand that `self` is `'a`; hence the
167        // context is also `'a`
168        //
169        // it is desirable to perform this safe change instead of taking every source as owned
170        self.name = unsafe { mem::transmute::<&'x str, &'a str>(name) };
171        self.contents = unsafe { mem::transmute::<&'x str, &'a str>(contents) };
172
173        Ok(())
174    }
175}