Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.

Commit c83acd3

Browse files
Merge pull request #3 from Fishrock123/refactor
refactor: many rust improvements
2 parents 2c87a01 + b9a7beb commit c83acd3

File tree

5 files changed

+166
-156
lines changed

5 files changed

+166
-156
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ Cargo.lock
88

99
# These are backup files generated by rustfmt
1010
**/*.rs.bk
11+
12+
node_modules/
13+
binaries/
14+
output/

cobhan/src/lib.rs

Lines changed: 131 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
use std::borrow::Cow;
2+
use std::collections::HashMap;
3+
use std::fs;
4+
use std::io::Write;
15
use std::os::raw::c_char;
26
use std::ptr::copy_nonoverlapping;
37
use std::slice::from_raw_parts;
4-
use serde_json::{Value};
5-
use std::collections::HashMap;
6-
use tempfile::NamedTempFile;
7-
use std::io::{Write};
8-
use std::fs;
98
use std::str;
109

10+
use serde_json::Value;
11+
use tempfile::NamedTempFile;
12+
1113
const ERR_NONE: i32 = 0;
1214

1315
//One of the provided pointers is NULL / nil / 0
@@ -42,14 +44,16 @@ static MAXIMUM_BUFFER_SIZE: i32 = i32::MAX;
4244

4345
#[cfg(feature = "cobhan_debug")]
4446
macro_rules! debug_print {
45-
($( $args:expr ),*) => { println!( $( $args ),* ); }
47+
($( $args:expr ),*) => { println!($($args ),*); };
4648
}
4749

4850
#[cfg(not(feature = "cobhan_debug"))]
4951
macro_rules! debug_print {
50-
($( $args:expr ),*) => {}
52+
($( $args:expr ),*) => {};
5153
}
5254

55+
/// ## Safety
56+
/// tbd
5357
pub unsafe fn cbuffer_to_vector(buffer: *const c_char) -> Result<Vec<u8>, i32> {
5458
if buffer.is_null() {
5559
debug_print!("cbuffer_to_vector: buffer is NULL");
@@ -61,8 +65,12 @@ pub unsafe fn cbuffer_to_vector(buffer: *const c_char) -> Result<Vec<u8>, i32> {
6165
debug_print!("cbuffer_to_vector: raw length field is {}", length);
6266

6367
if length > MAXIMUM_BUFFER_SIZE {
64-
debug_print!("cbuffer_to_vector: length {} is larger than MAXIMUM_BUFFER_SIZE ({})", length, MAXIMUM_BUFFER_SIZE);
65-
return Err(ERR_BUFFER_TOO_LARGE)
68+
debug_print!(
69+
"cbuffer_to_vector: length {} is larger than MAXIMUM_BUFFER_SIZE ({})",
70+
length,
71+
MAXIMUM_BUFFER_SIZE
72+
);
73+
return Err(ERR_BUFFER_TOO_LARGE);
6674
}
6775
if length < 0 {
6876
debug_print!("cbuffer_to_vector: calling temp_to_vector");
@@ -73,25 +81,8 @@ pub unsafe fn cbuffer_to_vector(buffer: *const c_char) -> Result<Vec<u8>, i32> {
7381
Ok(from_raw_parts(payload, length as usize).to_vec())
7482
}
7583

76-
unsafe fn temp_to_vector(payload: *const u8, length: i32) -> Result<Vec<u8>, i32> {
77-
let file_name;
78-
match str::from_utf8(from_raw_parts(payload, (0 - length) as usize)) {
79-
Ok(f) => file_name = f,
80-
Err(..) => {
81-
debug_print!("temp_to_vector: temp file name is invalid utf-8 string (length = {})", 0 - length);
82-
return Err(ERR_INVALID_UTF8);
83-
}
84-
}
85-
86-
return match fs::read(file_name) {
87-
Ok(s) => Ok(s),
88-
Err(_e) => {
89-
debug_print!("temp_to_vector: failed to read temporary file {}: {}", file_name, _e);
90-
Err(ERR_READ_TEMP_FILE_FAILED)
91-
}
92-
}
93-
}
94-
84+
/// ## Safety
85+
/// tbd
9586
pub unsafe fn cbuffer_to_string(buffer: *const c_char) -> Result<String, i32> {
9687
if buffer.is_null() {
9788
debug_print!("cbuffer_to_string: buffer is NULL");
@@ -103,49 +94,79 @@ pub unsafe fn cbuffer_to_string(buffer: *const c_char) -> Result<String, i32> {
10394
debug_print!("cbuffer_to_string: raw length field is {}", length);
10495

10596
if length > MAXIMUM_BUFFER_SIZE {
106-
debug_print!("cbuffer_to_string: length {} is larger than MAXIMUM_BUFFER_SIZE ({})", length, MAXIMUM_BUFFER_SIZE);
97+
debug_print!(
98+
"cbuffer_to_string: length {} is larger than MAXIMUM_BUFFER_SIZE ({})",
99+
length,
100+
MAXIMUM_BUFFER_SIZE
101+
);
107102
return Err(ERR_BUFFER_TOO_LARGE);
108103
}
109104

110105
debug_print!("cbuffer_to_string: raw length field is {}", length);
111106

112107
if length < 0 {
113108
debug_print!("cbuffer_to_string: calling temp_to_string");
114-
return temp_to_string(payload, length)
109+
return temp_to_string(payload, length);
115110
}
116111

117-
//Allocation: to_vec() is a clone/copy
118-
return match String::from_utf8(from_raw_parts(payload, length as usize).to_vec()) {
119-
Ok(input_str) => Ok(input_str),
120-
Err(..) => {
121-
debug_print!("cbuffer_to_string: payload is invalid utf-8 string (length = {})", length);
122-
Err(ERR_INVALID_UTF8)
123-
}
124-
}
112+
str::from_utf8(from_raw_parts(payload, length as usize))
113+
.map(|s| s.to_owned())
114+
.map_err(|_| {
115+
debug_print!(
116+
"cbuffer_to_string: payload is invalid utf-8 string (length = {})",
117+
length
118+
);
119+
ERR_INVALID_UTF8
120+
})
125121
}
126122

127123
unsafe fn temp_to_string(payload: *const u8, length: i32) -> Result<String, i32> {
128-
let file_name;
129-
match str::from_utf8(from_raw_parts(payload, (0 - length) as usize)) {
130-
Ok(f) => file_name = f,
131-
Err(..) => {
132-
debug_print!("temp_to_string: temp file name is invalid utf-8 string (length = {})", 0 - length);
133-
return Err(ERR_INVALID_UTF8);
134-
}
135-
}
124+
let file_name =
125+
str::from_utf8(from_raw_parts(payload, (0 - length) as usize)).map_err(|_| {
126+
debug_print!(
127+
"temp_to_string: temp file name is invalid utf-8 string (length = {})",
128+
0 - length
129+
);
130+
ERR_INVALID_UTF8
131+
})?;
136132

137133
debug_print!("temp_to_string: reading temp file {}", file_name);
138134

139-
return match fs::read_to_string(file_name) {
140-
Ok(s) => Ok(s),
141-
Err(_e) => {
142-
debug_print!("temp_to_string: Error reading temp file {}: {}", file_name, _e);
143-
Err(ERR_READ_TEMP_FILE_FAILED)
144-
}
145-
}
135+
fs::read_to_string(file_name).map_err(|_e| {
136+
debug_print!(
137+
"temp_to_string: Error reading temp file {}: {}",
138+
file_name,
139+
_e
140+
);
141+
ERR_READ_TEMP_FILE_FAILED
142+
})
143+
}
144+
145+
unsafe fn temp_to_vector(payload: *const u8, length: i32) -> Result<Vec<u8>, i32> {
146+
let file_name =
147+
str::from_utf8(from_raw_parts(payload, (0 - length) as usize)).map_err(|_| {
148+
debug_print!(
149+
"temp_to_vector: temp file name is invalid utf-8 string (length = {})",
150+
0 - length
151+
);
152+
ERR_INVALID_UTF8
153+
})?;
154+
155+
fs::read(file_name).map_err(|_e| {
156+
debug_print!(
157+
"temp_to_vector: failed to read temporary file {}: {}",
158+
file_name,
159+
_e
160+
);
161+
ERR_READ_TEMP_FILE_FAILED
162+
})
146163
}
147164

148-
pub unsafe fn cbuffer_to_hashmap_json(buffer: *const c_char) -> Result<HashMap<String,Value>, i32> {
165+
/// ## Safety
166+
/// tbd
167+
pub unsafe fn cbuffer_to_hashmap_json(
168+
buffer: *const c_char,
169+
) -> Result<HashMap<String, Value>, i32> {
149170
if buffer.is_null() {
150171
debug_print!("cbuffer_to_hashmap_json: buffer is NULL");
151172
return Err(ERR_NULL_PTR);
@@ -155,56 +176,50 @@ pub unsafe fn cbuffer_to_hashmap_json(buffer: *const c_char) -> Result<HashMap<S
155176
let payload = buffer.offset(BUFFER_HEADER_SIZE) as *const u8;
156177
debug_print!("cbuffer_to_hashmap_json: raw length field is {}", length);
157178

158-
159179
if length > MAXIMUM_BUFFER_SIZE {
160-
debug_print!("cbuffer_to_hashmap_json: length {} is larger than MAXIMUM_BUFFER_SIZE ({})", length, MAXIMUM_BUFFER_SIZE);
180+
debug_print!(
181+
"cbuffer_to_hashmap_json: length {} is larger than MAXIMUM_BUFFER_SIZE ({})",
182+
length,
183+
MAXIMUM_BUFFER_SIZE
184+
);
161185
return Err(ERR_BUFFER_TOO_LARGE);
162186
}
163187

164188
debug_print!("cbuffer_to_hashmap_json: raw length field is {}", length);
165189

166-
let json_str;
167-
let temp_string_result;
168-
if length >= 0 {
169-
match str::from_utf8(from_raw_parts(payload, length as usize)) {
170-
Ok(input_str) => json_str = input_str,
171-
Err(..) => {
172-
debug_print!("cbuffer_to_hashmap_json: payload is invalid utf-8 string (length = {})", length);
173-
return Err(ERR_INVALID_UTF8);
174-
}
175-
}
190+
let json_bytes = if length >= 0 {
191+
Cow::Borrowed(from_raw_parts(payload, length as usize))
176192
} else {
177-
debug_print!("cbuffer_to_hashmap_json: calling temp_to_string");
178-
match temp_to_string(payload, length) {
179-
Ok(string) => {
180-
temp_string_result = string;
181-
json_str = &temp_string_result;
182-
},
183-
Err(e) => return Err(e)
184-
}
185-
}
186-
187-
return match serde_json::from_str(&json_str) {
188-
Ok(json) => Ok(json),
189-
Err(_e) => {
190-
debug_print!("cbuffer_to_hashmap_json: serde_json::from_str / JSON decode failed {}", _e);
191-
Err(ERR_JSON_DECODE_FAILED)
192-
}
193-
}
193+
debug_print!("cbuffer_to_hashmap_json: calling temp_to_vector");
194+
Cow::Owned(temp_to_vector(payload, length)?)
195+
};
196+
197+
serde_json::from_slice(&json_bytes).map_err(|_e| {
198+
debug_print!(
199+
"cbuffer_to_hashmap_json: serde_json::from_slice / JSON decode failed {}",
200+
_e
201+
);
202+
ERR_JSON_DECODE_FAILED
203+
})
194204
}
195205

196-
pub unsafe fn hashmap_json_to_cbuffer(json: &HashMap<String,Value>, buffer: *mut c_char) -> i32 {
197-
//TODO: Use tovec?
198-
return match serde_json::to_string(&json) {
199-
Ok(json_str) => string_to_cbuffer(&json_str, buffer),
200-
Err(..) => ERR_JSON_ENCODE_FAILED
206+
/// ## Safety
207+
/// tbd
208+
pub unsafe fn hashmap_json_to_cbuffer(json: &HashMap<String, Value>, buffer: *mut c_char) -> i32 {
209+
match serde_json::to_vec(&json) {
210+
Ok(json_bytes) => bytes_to_cbuffer(&json_bytes, buffer),
211+
Err(_) => ERR_JSON_ENCODE_FAILED,
201212
}
202213
}
203214

215+
/// ## Safety
216+
/// tbd
204217
pub unsafe fn string_to_cbuffer(string: &str, buffer: *mut c_char) -> i32 {
205218
bytes_to_cbuffer(string.as_bytes(), buffer)
206219
}
207220

221+
/// ## Safety
222+
/// tbd
208223
pub unsafe fn bytes_to_cbuffer(bytes: &[u8], buffer: *mut c_char) -> i32 {
209224
if buffer.is_null() {
210225
debug_print!("bytes_to_cbuffer: buffer is NULL");
@@ -239,64 +254,57 @@ pub unsafe fn bytes_to_cbuffer(bytes: &[u8], buffer: *mut c_char) -> i32 {
239254
}
240255

241256
unsafe fn bytes_to_temp(bytes: &[u8], buffer: *mut c_char) -> i32 {
242-
let tmp_file_path;
243-
match write_new_file(bytes) {
244-
Ok(t) => tmp_file_path = t,
245-
Err(r) => return r
246-
}
247-
debug_print!("bytes_to_temp: write_new_file wrote {} bytes to {}", bytes.len(), tmp_file_path);
257+
// TODO: eventually replace this pattern with if-let once that is stable -jsenkpiel
258+
let tmp_file_path = match write_new_file(bytes) {
259+
Ok(t) => t,
260+
Err(r) => return r,
261+
};
262+
debug_print!(
263+
"bytes_to_temp: write_new_file wrote {} bytes to {}",
264+
bytes.len(),
265+
tmp_file_path
266+
);
248267

249268
let length = buffer as *mut i32;
250269
let tmp_file_path_len = tmp_file_path.len() as i32;
251270

252271
//NOTE: We explicitly test this so we don't recursively attempt to create temp files with string_to_cbuffer()
253272
if *length < tmp_file_path_len {
254273
//Temp file path won't fit in output buffer, we're out of luck
255-
debug_print!("bytes_to_temp: temp file path {} is larger than buffer capacity {}", tmp_file_path, *length);
274+
debug_print!(
275+
"bytes_to_temp: temp file path {} is larger than buffer capacity {}",
276+
tmp_file_path,
277+
*length
278+
);
256279
let _ = fs::remove_file(tmp_file_path);
257280
return ERR_BUFFER_TOO_SMALL;
258281
}
259282

260283
let result = string_to_cbuffer(&tmp_file_path, buffer);
261284
if result != ERR_NONE {
262-
debug_print!("bytes_to_temp: failed to store temp path {} in buffer", tmp_file_path);
285+
debug_print!(
286+
"bytes_to_temp: failed to store temp path {} in buffer",
287+
tmp_file_path
288+
);
263289
let _ = fs::remove_file(tmp_file_path);
264290
return result;
265291
}
266292

267293
*length = 0 - tmp_file_path_len;
268-
return result;
294+
295+
result
269296
}
270297

271298
unsafe fn write_new_file(bytes: &[u8]) -> Result<String, i32> {
272-
let mut tmpfile;
273-
match NamedTempFile::new() {
274-
Ok(f) => tmpfile = f,
275-
Err(..) => return Err(ERR_WRITE_TEMP_FILE_FAILED)
276-
}
277-
let bytes_len = bytes.len();
278-
279-
let bytes_written;
280-
match tmpfile.write_all(&bytes) {
281-
Ok(..) => bytes_written = bytes_len as i32,
282-
Err(..) => return Err(ERR_WRITE_TEMP_FILE_FAILED)
283-
}
299+
let mut tmpfile = NamedTempFile::new().map_err(|_| ERR_WRITE_TEMP_FILE_FAILED)?;
284300

285-
if (bytes_written as usize) != bytes_len {
301+
if tmpfile.write_all(bytes).is_err() {
286302
return Err(ERR_WRITE_TEMP_FILE_FAILED);
287-
}
303+
};
288304

289-
let result;
290-
match tmpfile.keep() {
291-
Ok(r) => result = r,
292-
Err(..) => return Err(ERR_WRITE_TEMP_FILE_FAILED)
293-
}
294-
let (_, path) = result;
305+
let (_, path) = tmpfile.keep().map_err(|_| ERR_WRITE_TEMP_FILE_FAILED)?;
295306

296-
return match path.into_os_string().into_string() {
297-
Ok(tmp_path) => Ok(tmp_path),
298-
Err(..) => {
299-
Err(ERR_WRITE_TEMP_FILE_FAILED)
300-
}
301-
}
307+
path.into_os_string()
308+
.into_string()
309+
.map_err(|_| ERR_WRITE_TEMP_FILE_FAILED)
302310
}

libcobhandemo/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ done
9999
##########
100100
# Test Rust dynamic library file using node
101101

102+
mkdir -p node-test/libcobhandemo/binaries/
102103
cp "target/${BUILD_DIR}/libcobhandemo${DYN_EXT}" "node-test/libcobhandemo/binaries/libcobhandemo-${DYN_SUFFIX}"
103104
npm -C node-test/libcobhandemo install
104105
pushd node-test/consumer-console-app

libcobhandemo/python-test/cobhan_demo_lib/cobhan_demo.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ class CobhanDemoLib(Cobhan):
1616
@classmethod
1717
def from_library_path(cls, library_root_path):
1818
instance = cls()
19-
instance._load_library(library_root_path, 'libcobhandemo', CobhanDemoLib.CDEFINES)
19+
instance.load_library(library_root_path, 'libcobhandemo', CobhanDemoLib.CDEFINES)
2020
return instance
2121

2222
@classmethod
2323
def from_library_file(cls, library_file_path):
2424
instance = cls()
25-
instance._load_library_direct(library_file_path, CobhanDemoLib.CDEFINES)
25+
instance.load_library_direct(library_file_path, CobhanDemoLib.CDEFINES)
2626
return instance
2727

2828
def to_upper(self, input):

0 commit comments

Comments
 (0)