1use crate::{ProgramError, ProgramResult};
7
8#[inline(always)]
14pub unsafe fn copy_nonoverlapping(dst: *mut u8, src: *const u8, len: usize) {
15 unsafe {
17 crate::syscalls::sol_memcpy_(dst, src, len as u64);
18 }
19}
20
21#[inline(always)]
27pub unsafe fn copy(dst: *mut u8, src: *const u8, len: usize) {
28 unsafe {
30 crate::syscalls::sol_memmove_(dst, src, len as u64);
31 }
32}
33
34#[inline(always)]
40pub unsafe fn fill(dst: *mut u8, byte: u8, len: usize) {
41 unsafe {
43 crate::syscalls::sol_memset_(dst, byte, len as u64);
44 }
45}
46
47#[inline(always)]
53pub unsafe fn compare(left: *const u8, right: *const u8, len: usize) -> core::cmp::Ordering {
54 let mut result = 0i32;
55 unsafe {
57 crate::syscalls::sol_memcmp_(left, right, len as u64, &mut result as *mut i32);
58 }
59 match result {
60 0 => core::cmp::Ordering::Equal,
61 value if value < 0 => core::cmp::Ordering::Less,
62 _ => core::cmp::Ordering::Greater,
63 }
64}
65
66#[inline]
68pub fn copy_bytes(dst: &mut [u8], src: &[u8]) -> ProgramResult {
69 if dst.len() < src.len() {
70 return Err(ProgramError::InvalidArgument);
71 }
72 if src.is_empty() {
73 return Ok(());
74 }
75 unsafe {
77 copy_nonoverlapping(dst.as_mut_ptr(), src.as_ptr(), src.len());
78 }
79 Ok(())
80}
81
82#[inline]
84pub fn move_within(
85 buffer: &mut [u8],
86 src_start: usize,
87 len: usize,
88 dst_start: usize,
89) -> ProgramResult {
90 let src_end = src_start
91 .checked_add(len)
92 .ok_or(ProgramError::InvalidArgument)?;
93 let dst_end = dst_start
94 .checked_add(len)
95 .ok_or(ProgramError::InvalidArgument)?;
96 if src_end > buffer.len() || dst_end > buffer.len() {
97 return Err(ProgramError::InvalidArgument);
98 }
99 if len == 0 || src_start == dst_start {
100 return Ok(());
101 }
102 unsafe {
104 copy(
105 buffer.as_mut_ptr().add(dst_start),
106 buffer.as_ptr().add(src_start),
107 len,
108 );
109 }
110 Ok(())
111}
112
113#[inline]
115pub fn fill_bytes(buffer: &mut [u8], byte: u8) {
116 if buffer.is_empty() {
117 return;
118 }
119 unsafe {
121 fill(buffer.as_mut_ptr(), byte, buffer.len());
122 }
123}
124
125#[inline(always)]
127pub fn zero_bytes(buffer: &mut [u8]) {
128 fill_bytes(buffer, 0);
129}
130
131#[inline]
133pub fn compare_bytes(left: &[u8], right: &[u8]) -> core::cmp::Ordering {
134 let prefix_len = core::cmp::min(left.len(), right.len());
135 if prefix_len != 0 {
136 let prefix_order = unsafe { compare(left.as_ptr(), right.as_ptr(), prefix_len) };
138 if prefix_order != core::cmp::Ordering::Equal {
139 return prefix_order;
140 }
141 }
142 left.len().cmp(&right.len())
143}
144
145#[inline]
147pub fn bytes_eq(left: &[u8], right: &[u8]) -> bool {
148 left.len() == right.len() && compare_bytes(left, right) == core::cmp::Ordering::Equal
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn copy_bytes_copies_prefix() {
157 let mut dst = [0u8; 5];
158 copy_bytes(&mut dst, &[1, 2, 3]).unwrap();
159 assert_eq!(dst, [1, 2, 3, 0, 0]);
160 }
161
162 #[test]
163 fn move_within_allows_overlap() {
164 let mut data = [1u8, 2, 3, 4, 5];
165 move_within(&mut data, 0, 4, 1).unwrap();
166 assert_eq!(data, [1, 1, 2, 3, 4]);
167 }
168
169 #[test]
170 fn fill_and_compare_bytes() {
171 let mut data = [9u8; 4];
172 zero_bytes(&mut data);
173 assert_eq!(data, [0u8; 4]);
174 assert!(bytes_eq(&data, &[0, 0, 0, 0]));
175 assert_eq!(compare_bytes(&[1, 2], &[1, 3]), core::cmp::Ordering::Less);
176 }
177}