ion/
utils.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use std::mem::MaybeUninit;
8use std::path::{Component, Path, PathBuf};
9use std::slice;
10use std::slice::Iter;
11
12/// Normalises a [Path] by removing all `./` and resolving all `../` simplistically.
13/// This function does not follow symlinks and may result in unexpected behaviour.
14pub fn normalise_path<P: AsRef<Path>>(path: P) -> PathBuf {
15	let mut buf = PathBuf::new();
16	let segments = path.as_ref().components();
17
18	for segment in segments {
19		match segment {
20			Component::ParentDir => {
21				let len = buf.components().count();
22				if len == 0 || buf.components().all(|c| matches!(c, Component::ParentDir)) {
23					buf.push("..");
24				} else {
25					buf.pop();
26				}
27			}
28			Component::CurDir => {}
29			segment => buf.push(segment),
30		}
31	}
32	buf
33}
34
35pub trait BoxExt<T> {
36	fn into_raw_parts(self) -> (*mut T, usize);
37
38	unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self;
39}
40
41impl<T> BoxExt<T> for Box<[T]> {
42	fn into_raw_parts(self) -> (*mut T, usize) {
43		let len = self.len();
44		(Box::into_raw(self).cast::<T>(), len)
45	}
46
47	unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
48		unsafe {
49			let slice = slice::from_raw_parts_mut(ptr, len);
50			Box::from_raw(slice)
51		}
52	}
53}
54
55#[derive(Clone, Copy, Debug)]
56pub struct ArrayVec<const CAP: usize, T: Copy> {
57	elements: [MaybeUninit<T>; CAP],
58	len: usize,
59}
60
61impl<const CAP: usize, T: Copy> ArrayVec<CAP, T> {
62	pub const fn new() -> ArrayVec<CAP, T> {
63		ArrayVec {
64			elements: unsafe { MaybeUninit::uninit().assume_init() },
65			len: 0,
66		}
67	}
68
69	pub const fn len(&self) -> usize {
70		self.len
71	}
72
73	pub const fn is_empty(&self) -> bool {
74		self.len() == 0
75	}
76
77	pub const fn is_full(&self) -> bool {
78		self.len() == CAP
79	}
80
81	pub const fn push(mut self, element: T) -> ArrayVec<CAP, T> {
82		assert!(self.len < CAP, "Exceeded capacity of ArrayVec.");
83		self.elements[self.len] = MaybeUninit::new(element);
84		self.len += 1;
85		self
86	}
87
88	pub const fn pop(mut self) -> (ArrayVec<CAP, T>, Option<T>) {
89		if self.len == 0 {
90			return (self, None);
91		}
92		let element = unsafe { self.elements[self.len].assume_init() };
93		self.len -= 1;
94		(self, Some(element))
95	}
96
97	pub const fn get(&self, index: usize) -> Option<&T> {
98		if self.is_empty() || index >= self.len() {
99			return None;
100		}
101		Some(unsafe { self.elements[index].assume_init_ref() })
102	}
103
104	pub const fn truncate(mut self, new_len: usize) -> ArrayVec<CAP, T> {
105		if new_len >= self.len {
106			return self;
107		}
108		self.len = new_len;
109		self
110	}
111
112	pub fn iter(&self) -> Iter<'_, T> {
113		unsafe { slice::from_raw_parts(self.elements.as_ptr().cast::<T>(), self.len()).iter() }
114	}
115}
116
117impl<const CAP: usize, T: Copy> Default for ArrayVec<CAP, T> {
118	fn default() -> ArrayVec<CAP, T> {
119		ArrayVec::new()
120	}
121}
122
123pub mod test {
124	use mozjs::jsapi::{JSAutoRealm, JSObject};
125	use mozjs::rust::{JSEngine, Runtime};
126
127	use crate::{Context, default_new_global};
128
129	pub struct TestRuntime {
130		pub realm: JSAutoRealm,
131		pub global: *mut JSObject,
132		pub cx: Context,
133		pub runtime: Runtime,
134		pub engine: JSEngine,
135	}
136
137	impl TestRuntime {
138		pub fn new() -> TestRuntime {
139			let engine = JSEngine::init().unwrap();
140			let runtime = Runtime::new(engine.handle());
141
142			let cx = Context::from_runtime(&runtime);
143			let global = default_new_global(&cx);
144			let realm = JSAutoRealm::new(cx.as_ptr(), global.handle().get());
145
146			TestRuntime {
147				realm,
148				global: global.handle().get(),
149				cx,
150				runtime,
151				engine,
152			}
153		}
154	}
155
156	impl Default for TestRuntime {
157		fn default() -> TestRuntime {
158			TestRuntime::new()
159		}
160	}
161}