-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(buffer): implement some static and prototype methods #869
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Some comments!
fn get_write_parameters(args: &Rest<Value<'_>>, len: usize) -> Result<(usize, usize, String)> { | ||
let encoding = "utf8".to_owned(); | ||
|
||
match (args.0.first(), args.0.get(1), args.0.get(2)) { | ||
(Some(v1), _, _) if v1.as_string().is_some() => { | ||
Ok((0, len, v1.as_string().unwrap().to_string()?)) | ||
}, | ||
|
||
(Some(v1), Some(v2), _) if v2.as_string().is_some() => { | ||
let offset = v1.as_int().unwrap_or(0) as usize; | ||
Ok((offset, len - offset, v2.as_string().unwrap().to_string()?)) | ||
}, | ||
|
||
(Some(v1), Some(v2), Some(v3)) => { | ||
let offset = v1.as_int().unwrap_or(0) as usize; | ||
Ok(( | ||
offset, | ||
v2.as_int() | ||
.map_or(len - offset, |l| (l as usize).min(len - offset)), | ||
v3.as_string().map_or(encoding, |s| s.to_string().unwrap()), | ||
)) | ||
}, | ||
|
||
(Some(v1), Some(v2), None) => { | ||
let offset = v1.as_int().unwrap_or(0) as usize; | ||
Ok(( | ||
offset, | ||
v2.as_int() | ||
.map_or(len - offset, |l| (l as usize).min(len - offset)), | ||
encoding, | ||
)) | ||
}, | ||
|
||
(Some(v1), None, None) => { | ||
let offset = v1.as_int().unwrap_or(0) as usize; | ||
Ok((offset, len - offset, encoding)) | ||
}, | ||
|
||
_ => Ok((0, len, encoding)), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seams pretty complex. Can we simplify arg parsing? Maybe use Opt instead of Rest and pass each of the opts. This is done in many places, for instance see how we do with child_process arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into the implementation of child_process but didn't find anything useful.
What makes parameter analysis difficult this time is that different types of encodings can appear for the first, second and third arguments.
From top to bottom, I expect the following patterns, which makes branching complicated:
- encoding
- offset, encoding
- offset, length, encoding
- offset, length
- offset
- none
It might be possible to implement this more trickily using if statements, but do you have any good ideas for a cleaner implementation?
fn write_int32_be<'js>( | ||
this: This<Object<'js>>, | ||
ctx: Ctx<'js>, | ||
value: i32, | ||
offset: Opt<i32>, | ||
) -> Result<usize> { | ||
let source_slice = [ | ||
(value >> 24) as u8, | ||
(value >> 16) as u8, | ||
(value >> 8) as u8, | ||
value as u8, | ||
]; | ||
let offset = offset.0.unwrap_or_default(); | ||
let buf_length = this.0.len().try_into().unwrap_or(i32::MAX); | ||
|
||
if offset < 0 || offset + source_slice.len() as i32 > buf_length { | ||
return Err(Exception::throw_range( | ||
&ctx, | ||
"The specified offset is out of range", | ||
)); | ||
} | ||
|
||
let offset = offset as usize; | ||
|
||
let target = ObjectBytes::from(&ctx, this.0.as_inner())?; | ||
|
||
let mut writable_length = 0; | ||
|
||
if let Some((array_buffer, _, _)) = target.get_array_buffer()? { | ||
let raw = array_buffer | ||
.as_raw() | ||
.ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED) | ||
.or_throw(&ctx)?; | ||
|
||
let target_bytes = unsafe { slice::from_raw_parts_mut(raw.ptr.as_ptr(), raw.len) }; | ||
|
||
writable_length = offset + source_slice.len(); | ||
|
||
target_bytes[offset..writable_length].copy_from_slice(&source_slice); | ||
} | ||
|
||
Ok(writable_length) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this a bit more generic to support all write methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I can do it. However, I won't have much time for a few days from today, so please be patient.
fn maybeuninit_to_u8(vec: Vec<MaybeUninit<u8>>) -> Vec<u8> { | ||
let len = vec.len(); | ||
let capacity = vec.capacity(); | ||
let ptr = vec.as_ptr() as *mut u8; | ||
|
||
std::mem::forget(vec); | ||
|
||
unsafe { Vec::from_raw_parts(ptr, len, capacity) } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate what this does. Please add a safety comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would comments like this help you understand?
This conversion is safe because MaybeUninit has the same memory layout as u8, meaning the underlying bytes are identical. Since Vec<MaybeUninit> and Vec share the same memory representation, a simple reinterpretation of the pointer is valid.
Additionally, Vec::from_raw_parts correctly reconstructs the vector using the original length and capacity, ensuring that memory ownership remains consistent. The call to std::mem::forget(vec) prevents the original Vec<MaybeUninit> from being dropped, avoiding double frees or memory corruption.
However, this conversion is only safe if all elements of MaybeUninit are properly initialized. If any uninitialized values exist, reading them as u8 would lead to undefined behavior.
Description of changes
This PR implements some methods that I need for my project.
Checklist
tests/unit
and/or in Rust for my feature if neededmake fix
to format JS and apply Clippy auto fixesmake check
types/
directoryBy submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.