diff --git a/src/main.rs b/src/main.rs index 75a26c8c..c618dfff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,13 @@ mod example { use crate::v8::inspector::channel::*; use crate::v8::*; + // Using repr(C) to preserve field ordering and test that everything works + // when the ChannelBase field is not the first element of the struct. + #[repr(C)] pub struct TestChannel { - a: i32, + field1: i32, channel_base: ChannelBase, - b: i32, + field2: f64, } impl ChannelImpl for TestChannel { @@ -41,8 +44,8 @@ mod example { pub fn new() -> Self { Self { channel_base: ChannelBase::new::(), - a: 2, - b: 3, + field1: -42, + field2: 4.2, } } } @@ -54,8 +57,8 @@ fn main() { use example::*; let mut ex = TestChannel::new(); let chan = ex.as_channel_mut(); - let message = b"hello"; - let message = StringView::from(&message[..]); + let message: &[u8] = b"hello"; + let message = StringView::from(message); let message = StringBuffer::create(&message); chan.sendResponse(3, message); } diff --git a/src/v8/platform/task.rs b/src/v8/platform/task.rs index b0c01d9a..13e1aa42 100644 --- a/src/v8/platform/task.rs +++ b/src/v8/platform/task.rs @@ -173,17 +173,17 @@ mod tests { // when the TaskBase field is not the first element of the struct. #[repr(C)] pub struct TestTask { - f1: i32, + field1: i32, base: TaskBase, - f2: f64, + field2: f64, } impl TestTask { pub fn new() -> Self { Self { base: TaskBase::new::(), - f1: 42, - f2: 4.2, + field1: -42, + field2: 4.2, } } } @@ -207,17 +207,15 @@ mod tests { } #[test] - fn test_v8_platform_task() { + fn test_task() { { - let mut v = TestTask::new(); - v.Run(); + TestTask::new().Run(); } assert_eq!(RUN_COUNT.swap(0, SeqCst), 1); assert_eq!(DROP_COUNT.swap(0, SeqCst), 1); { - let b = Box::new(TestTask::new()); - b.into_unique_ptr(); + Box::new(TestTask::new()).into_unique_ptr(); } assert_eq!(RUN_COUNT.swap(0, SeqCst), 0); assert_eq!(DROP_COUNT.swap(0, SeqCst), 1); diff --git a/src/v8/string_buffer.rs b/src/v8/string_buffer.rs index 4b25efe9..e9fa396d 100644 --- a/src/v8/string_buffer.rs +++ b/src/v8/string_buffer.rs @@ -43,3 +43,25 @@ impl Delete for StringBuffer { unsafe { v8_inspector__StringBuffer__DELETE(self) } } } + +mod tests { + use super::*; + + #[test] + fn test_string_buffer() { + let chars = b"Hello Venus!"; + let mut buf = { + let view1 = StringView::from(&chars[..]); + StringBuffer::create(&view1) + }; + let view2 = buf.as_mut().unwrap().string(); + + let mut count = 0usize; + for (c1, c2) in chars.iter().copied().map(|c| c as u16).zip(view2) { + assert_eq!(c1, c2); + count += 1; + } + assert_eq!(count, chars.len()); + assert_eq!(count, view2.length()); + } +} diff --git a/src/v8/string_view.rs b/src/v8/string_view.rs index 927348d0..d986d2cc 100644 --- a/src/v8/string_view.rs +++ b/src/v8/string_view.rs @@ -1,3 +1,5 @@ +use std::iter::ExactSizeIterator; +use std::iter::IntoIterator; use std::marker::PhantomData; use std::ops::Deref; use std::ptr::null; @@ -35,7 +37,7 @@ use std::slice; // same size. TODO: find/open upstream issue to allow #[repr(bool)] support. #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Debug)] pub enum StringView<'a> { // Do not reorder! U16(CharacterArray<'a, u16>), @@ -70,8 +72,8 @@ impl<'a> StringView<'a> { pub fn length(&self) -> usize { match self { - Self::U16(v) => v.m_length, - Self::U8(v) => v.m_length, + Self::U16(v) => v.len(), + Self::U8(v) => v.len(), } } @@ -90,6 +92,15 @@ impl<'a> StringView<'a> { } } +impl<'a: 'b, 'b> IntoIterator for &'a StringView<'b> { + type IntoIter = StringViewIterator<'a, 'b>; + type Item = u16; + + fn into_iter(self) -> Self::IntoIter { + StringViewIterator { view: self, pos: 0 } + } +} + #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct CharacterArray<'a, T> { @@ -99,7 +110,7 @@ pub struct CharacterArray<'a, T> { } impl CharacterArray<'static, u8> { - fn empty() -> Self { + pub fn empty() -> Self { Self { m_length: 0, m_characters: null(), @@ -108,6 +119,25 @@ impl CharacterArray<'static, u8> { } } +impl<'a, T> CharacterArray<'a, T> +where + T: Copy, +{ + #[inline(always)] + fn len(&self) -> usize { + self.m_length + } + + #[inline(always)] + fn get_at(&self, index: usize) -> Option { + if index < self.m_length { + Some(unsafe { *self.m_characters.add(index) }) + } else { + None + } + } +} + impl<'a, T> From<&'a [T]> for CharacterArray<'a, T> { fn from(v: &'a [T]) -> Self { Self { @@ -133,3 +163,46 @@ impl<'a, T> Deref for CharacterArray<'a, T> { unsafe { slice::from_raw_parts(m_characters, m_length) } } } + +#[derive(Copy, Clone, Debug)] +pub struct StringViewIterator<'a: 'b, 'b> { + view: &'a StringView<'b>, + pos: usize, +} + +impl<'a: 'b, 'b> Iterator for StringViewIterator<'a, 'b> { + type Item = u16; + + fn next(&mut self) -> Option { + let result = Some(match self.view { + StringView::U16(v) => v.get_at(self.pos)?, + StringView::U8(v) => v.get_at(self.pos)? as u16, + }); + self.pos += 1; + result + } +} + +impl<'a: 'b, 'b> ExactSizeIterator for StringViewIterator<'a, 'b> { + fn len(&self) -> usize { + self.view.length() + } +} + +mod tests { + use super::*; + + #[test] + fn test_string_view() { + let chars = b"Hello world!"; + let view = StringView::from(&chars[..]); + + let mut count = 0usize; + for (c1, c2) in chars.iter().copied().map(|c| c as u16).zip(&view) { + assert_eq!(c1, c2); + count += 1; + } + assert_eq!(count, chars.len()); + assert_eq!(count, view.length()); + } +}