Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: mojo/public/rust/src/bindings/encoding.rs

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/public/rust/src/bindings/decoding.rs ('k') | mojo/public/rust/src/bindings/macros.rs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use bindings::mojom::MOJOM_NULL_POINTER;
6 use bindings::util;
7
8 use std::mem;
9 use std::ptr;
10 use std::ops::{Add, AddAssign, Sub, Mul, Div, Rem};
11 use std::vec::Vec;
12
13 use system::UntypedHandle;
14
15 /// Represents some count of bits.
16 ///
17 /// Used to distinguish when we have a bit and a byte
18 /// count. The byte count will go in a usize, while we
19 /// can use this structure to safely count bits without
20 /// running into some subtle bugs or crazy errors.
21 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
22 pub struct Bits(pub usize);
23
24 impl Bits {
25 /// Convert bit representation to bytes, rounding up to the nearest byte.
26 pub fn as_bytes(self) -> usize {
27 util::bits_to_bytes(self.0)
28 }
29
30 /// Convert to a number of bytes plus the number of bits leftover
31 /// that could not fit in a full byte.
32 pub fn as_bits_and_bytes(self) -> (Bits, usize) {
33 (Bits(self.0 & 7), self.0 >> 3)
34 }
35
36 /// Return 1 left-shifted by the amount of bits stored here.
37 ///
38 /// Only guaranteed to work for up to 8 bits.
39 pub fn as_set_bit(self) -> u8 {
40 debug_assert!(self.0 < 8);
41 1 << (self.0 & 7)
42 }
43
44 pub fn checked_mul(self, val: usize) -> Option<Bits> {
45 match val.checked_mul(self.0) {
46 Some(result) => Some(Bits(result)),
47 None => None,
48 }
49 }
50
51 /// Align the bits to some number of bytes.
52 pub fn align_to_bytes(&mut self, bytes: usize) {
53 self.0 = util::align_bytes(self.0, 8 * bytes);
54 }
55 }
56
57 impl Add for Bits {
58 type Output = Self;
59 fn add(self, rhs: Self) -> Self {
60 Bits(self.0 + rhs.0)
61 }
62 }
63
64 impl AddAssign for Bits {
65 fn add_assign(&mut self, rhs: Self) {
66 self.0 += rhs.0
67 }
68 }
69
70 impl Mul<usize> for Bits {
71 type Output = Self;
72 fn mul(self, rhs: usize) -> Self {
73 Bits(self.0 * rhs)
74 }
75 }
76
77 /// This trait is intended to be used by Mojom primitive values
78 /// in order to be identified in generic contexts.
79 pub trait MojomNumeric: Copy + Clone + Sized + Add<Self> + Sub<Self, Output=Self > + Mul<Self> +
80 Div<Self, Output=Self> + Rem<Self, Output=Self> + PartialEq<Self> + Default {
81
82 /// Converts the primitive to a little-endian representation (the mojom endianne ss).
83 fn to_mojom_endian(self) -> Self;
84 }
85
86 macro_rules! impl_mojom_numeric_for_prim {
87 ($($t:ty),*) => {
88 $(
89 impl MojomNumeric for $t {
90 fn to_mojom_endian(self) -> $t { self.to_le() }
91 }
92 )*
93 }
94 }
95
96 impl_mojom_numeric_for_prim!(i8, i16, i32, i64, u8, u16, u32, u64);
97
98 impl MojomNumeric for f32 {
99 fn to_mojom_endian(self) -> f32 {
100 unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self).to_ le()) }
101 }
102 }
103
104 impl MojomNumeric for f64 {
105 fn to_mojom_endian(self) -> f64 {
106 unsafe { mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self).to_ le()) }
107 }
108 }
109
110 /// Align to the Mojom default of 8 bytes.
111 pub fn align_default(bytes: usize) -> usize {
112 util::align_bytes(bytes, 8)
113 }
114
115 /// The size in bytes of any data header.
116 pub const DATA_HEADER_SIZE: usize = 8;
117
118 /// A value that goes in the second u32 of a
119 /// a data header.
120 ///
121 /// Since the data header can head many types,
122 /// this enum represents all the kinds of data
123 /// that can end up in a data header.
124 #[derive(Clone, Copy)]
125 pub enum DataHeaderValue {
126 Elements(u32),
127 Version(u32),
128 UnionTag(u32),
129 }
130
131 impl DataHeaderValue {
132 /// Get the raw u32 value.
133 fn as_raw(self) -> u32 {
134 match self {
135 DataHeaderValue::Elements(v) => v,
136 DataHeaderValue::Version(v) => v,
137 DataHeaderValue::UnionTag(v) => v,
138 }
139 }
140 }
141
142 /// A data header is placed at the beginning of every serialized
143 /// Mojom object, providing its size as well as some extra meta-data.
144 ///
145 /// The meta-data should always come from a DataHeaderValue.
146 pub struct DataHeader {
147 size: u32,
148 data: u32,
149 }
150
151 impl DataHeader {
152 /// Create a new DataHeader.
153 pub fn new(size: usize, data: DataHeaderValue) -> DataHeader {
154 DataHeader {
155 size: size as u32,
156 data: data.as_raw(),
157 }
158 }
159
160 /// Getter for size.
161 pub fn size(&self) -> u32 {
162 self.size
163 }
164
165 /// Getter for extra meta-data.
166 pub fn data(&self) -> u32 {
167 self.data
168 }
169 }
170
171 /// This context object represents an encoding/decoding context.
172 #[derive(Clone, Default)]
173 pub struct Context {
174 /// An index representing an encoding state.
175 id: usize,
176
177 /// Whether or not our current context is directly inside of
178 /// a union.
179 is_union: bool,
180 }
181
182 impl Context {
183 /// Create a new context with all data default.
184 pub fn new(id: usize) -> Context {
185 Context {
186 id: id,
187 is_union: false,
188 }
189 }
190
191 /// Getter for the encoding state ID.
192 pub fn id(&self) -> usize {
193 self.id
194 }
195
196 /// Getter for whether or not we are in a union.
197 pub fn is_union(&self) -> bool {
198 self.is_union
199 }
200
201 /// Change whether or not we are inside of a union and create that
202 /// as a new context.
203 pub fn set_is_union(&self, value: bool) -> Context {
204 let mut new_context = self.clone();
205 new_context.is_union = value;
206 new_context
207 }
208 }
209
210 /// An encoding state represents the encoding logic for a single
211 /// Mojom object that is NOT inlined, such as a struct or an array.
212 pub struct EncodingState<'slice> {
213 /// The buffer the state may write to.
214 data: &'slice mut [u8],
215
216 /// The offset of this serialized object into the overall buffer.
217 global_offset: usize,
218
219 /// The current offset within 'data'.
220 offset: usize,
221
222 /// The current bit offset within 'data'.
223 bit_offset: Bits,
224 }
225
226 impl<'slice> EncodingState<'slice> {
227 /// Create a new encoding state.
228 ///
229 /// Note: the encoder will not allocate a buffer for you, rather
230 /// a pre-allocated buffer must be passed in.
231 pub fn new(buffer: &'slice mut [u8],
232 header: &DataHeader,
233 offset: usize)
234 -> EncodingState<'slice> {
235 let mut state = EncodingState {
236 data: buffer,
237 global_offset: offset,
238 offset: 0,
239 bit_offset: Bits(0),
240 };
241 state.write(header.size());
242 state.write(header.data());
243 state
244 }
245
246 /// Align the encoding state to the next byte.
247 pub fn align_to_byte(&mut self) {
248 if self.bit_offset > Bits(0) {
249 self.offset += 1;
250 self.bit_offset = Bits(0);
251 }
252 }
253
254 /// Align the encoding state to the next 'bytes' boundary.
255 pub fn align_to_bytes(&mut self, bytes: usize) {
256 self.offset = util::align_bytes(self.offset, bytes);
257 }
258
259 /// Write a primitive into the buffer.
260 fn write<T: MojomNumeric>(&mut self, data: T) {
261 let num_bytes = mem::size_of::<T>();
262 let bytes = data.to_mojom_endian();
263 debug_assert!(num_bytes + self.offset <= self.data.len());
264 unsafe {
265 ptr::copy_nonoverlapping(mem::transmute::<&T, *const u8>(&bytes),
266 (&mut self.data[self.offset..]).as_mut_ptr( ),
267 num_bytes);
268 }
269 self.bit_offset = Bits(0);
270 self.offset += num_bytes;
271 }
272
273 /// Encode a primitive into the buffer, naturally aligning it.
274 pub fn encode<T: MojomNumeric>(&mut self, data: T) {
275 self.align_to_byte();
276 self.align_to_bytes(mem::size_of::<T>());
277 self.write(data);
278 }
279
280 /// Encode a boolean value into the buffer as one bit.
281 pub fn encode_bool(&mut self, data: bool) {
282 let offset = self.offset;
283 if data {
284 self.data[offset] |= self.bit_offset.as_set_bit();
285 }
286 self.bit_offset += Bits(1);
287 let (bits, bytes) = self.bit_offset.as_bits_and_bytes();
288 self.offset += bytes;
289 self.bit_offset = bits;
290 }
291
292 /// Encode a null union into the buffer.
293 pub fn encode_null_union(&mut self) {
294 self.align_to_byte();
295 self.align_to_bytes(8);
296 self.write(0 as u32); // Size
297 self.write(0 as u32); // Tag
298 self.write(0 as u64); // Data
299 }
300
301 /// Encode a null pointer into the buffer.
302 pub fn encode_null_pointer(&mut self) {
303 self.align_to_byte();
304 self.align_to_bytes(8);
305 self.encode(MOJOM_NULL_POINTER);
306 }
307
308 /// Encode a null handle into the buffer.
309 pub fn encode_null_handle(&mut self) {
310 self.align_to_byte();
311 self.align_to_bytes(4);
312 self.encode(-1 as i32);
313 }
314
315 /// Encode a non-null pointer into the buffer.
316 ///
317 /// 'location' is an absolute location in the global buffer, but
318 /// Mojom pointers are offsets relative to the pointer, so we
319 /// perform that conversion here before writing.
320 pub fn encode_pointer(&mut self, location: u64) {
321 self.align_to_byte();
322 self.align_to_bytes(8);
323 let current_location = (self.global_offset + self.offset) as u64;
324 debug_assert!(location >= current_location);
325 self.encode(location - current_location);
326 }
327 }
328
329 /// A struct that will encode a given Mojom object and convert it into
330 /// bytes and a vector of handles.
331 pub struct Encoder<'slice> {
332 bytes: usize,
333 buffer: Option<&'slice mut [u8]>,
334 states: Vec<EncodingState<'slice>>,
335 handles: Vec<UntypedHandle>,
336 }
337
338 impl<'slice> Encoder<'slice> {
339 /// Create a new Encoder.
340 pub fn new(buffer: &'slice mut [u8]) -> Encoder<'slice> {
341 Encoder {
342 bytes: 0,
343 buffer: Some(buffer),
344 states: Vec::new(),
345 handles: Vec::new(),
346 }
347 }
348
349 /// Get the current encoded size (useful for writing pointers).
350 pub fn size(&self) -> usize {
351 self.bytes
352 }
353
354 /// Start encoding a new object with its data header.
355 ///
356 /// Creates a new encoding state for the object.
357 pub fn add(&mut self, header: &DataHeader) -> Option<Context> {
358 let buf = self.buffer.take().unwrap();
359 if buf.len() < (header.size() as usize) {
360 self.buffer = Some(buf);
361 return None;
362 }
363 let obj_bytes = header.size() as usize;
364 let (claimed, rest) = buf.split_at_mut(obj_bytes);
365 self.states.push(EncodingState::new(claimed, header, self.bytes));
366 self.bytes += obj_bytes;
367 let padding_bytes = align_default(obj_bytes) - obj_bytes;
368 if padding_bytes <= rest.len() {
369 let (_, new_buffer) = rest.split_at_mut(padding_bytes);
370 self.bytes += padding_bytes;
371 self.buffer = Some(new_buffer);
372 } else {
373 self.buffer = Some(rest);
374 }
375 Some(Context::new(self.states.len() - 1))
376 }
377
378 /// Adds a handle and returns an offset to that handle in the
379 /// final handle vector.
380 pub fn add_handle(&mut self, handle: UntypedHandle) -> usize {
381 self.handles.push(handle);
382 self.handles.len() - 1
383 }
384
385 /// Immutably borrow an encoding state via Context.
386 pub fn get(&self, context: &Context) -> &EncodingState<'slice> {
387 &self.states[context.id()]
388 }
389
390 /// Mutably borrow an encoding state via Context.
391 pub fn get_mut(&mut self, context: &Context) -> &mut EncodingState<'slice> {
392 &mut self.states[context.id()]
393 }
394
395 /// Signal to finish encoding by destroying the Encoder and returning the fi nal
396 /// handle vector.
397 ///
398 /// Note: No byte buffer is returned as that is pre-allocated.
399 pub fn unwrap(self) -> Vec<UntypedHandle> {
400 self.handles
401 }
402 }
OLDNEW
« no previous file with comments | « mojo/public/rust/src/bindings/decoding.rs ('k') | mojo/public/rust/src/bindings/macros.rs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698