1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Helper traits to convert byte signedness for Java interop
16 
17 /// A helper trait to bitcast data to its signed representation
18 pub trait ToSigned {
19     /// The signed version of this type.
20     type Signed;
21 
22     /// Bitcast to signed
to_signed(self) -> Self::Signed23     fn to_signed(self) -> Self::Signed;
24 }
25 
26 impl<'a> ToSigned for &'a [u8] {
27     type Signed = &'a [i8];
28 
29     #[allow(unsafe_code)]
to_signed(self) -> Self::Signed30     fn to_signed(self) -> Self::Signed {
31         let len = self.len();
32         // Safety:
33         // u8 and i8 have the same layout and the lifetime is maintained
34         unsafe { core::slice::from_raw_parts(self.as_ptr() as *const i8, len) }
35     }
36 }
37 
38 /// A helper trait to bitcast data to its unsigned representation
39 pub trait ToUnsigned {
40     /// The unsigned version of this type.
41     type Unsigned;
42 
43     /// Bitcast to unsigned
to_unsigned(self) -> Self::Unsigned44     fn to_unsigned(self) -> Self::Unsigned;
45 }
46 
47 impl<'a> ToUnsigned for &'a [i8] {
48     type Unsigned = &'a [u8];
49 
50     #[allow(unsafe_code)]
to_unsigned(self) -> Self::Unsigned51     fn to_unsigned(self) -> Self::Unsigned {
52         let len = self.len();
53         // Safety:
54         // u8 and i8 have the same layout and the lifetime is maintained
55         unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, len) }
56     }
57 }
58 
59 #[cfg(test)]
60 mod test {
61     use super::*;
62 
63     #[test]
test_to_signed()64     fn test_to_signed() {
65         let input: &[u8] = &[1, 2, 3, 0, 0xff, 0xfe];
66         let expected: &[i8] = &[1, 2, 3, 0, -1, -2];
67 
68         assert_eq!(expected, input.to_signed());
69     }
70 
71     #[test]
test_to_unsigned()72     fn test_to_unsigned() {
73         let input: &[i8] = &[1, 2, 3, 0, -1, -2];
74         let expected: &[u8] = &[1, 2, 3, 0, 0xff, 0xfe];
75 
76         assert_eq!(expected, input.to_unsigned());
77     }
78 
79     #[test]
test_roundtrip_unsigned()80     fn test_roundtrip_unsigned() {
81         let case: &[u8] = &[1, 2, 3, 0, 0xff, 0xfe];
82         assert_eq!(case, case.to_signed().to_unsigned());
83     }
84 
85     #[test]
test_roundtrip_signed()86     fn test_roundtrip_signed() {
87         let case: &[i8] = &[1, 2, 3, 0, -1, -2];
88         assert_eq!(case, case.to_unsigned().to_signed());
89     }
90 }
91