Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 110 additions & 3 deletions libdd-profiling-ffi/src/profiles/profiles_dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

use crate::arc_handle::ArcHandle;
use crate::profile_status::ProfileStatus;
use crate::profiles::utf8::Utf8Option;
use crate::profiles::utf8::{self, Utf8Option};
use crate::profiles::{ensure_non_null_insert, ensure_non_null_out_parameter};
use crate::ProfileError;
use libdd_common_ffi::slice::CharSlice;
use libdd_common_ffi::slice::{CharSlice, Slice};
use libdd_common_ffi::MutSlice;
use libdd_profiling::profiles::collections::StringRef;
use libdd_profiling::profiles::datatypes::{
Function2, FunctionId2, Mapping2, MappingId2, ProfilesDictionary, StringId2,
Expand Down Expand Up @@ -175,11 +176,49 @@ pub unsafe extern "C" fn ddog_prof_ProfilesDictionary_insert_str(
ensure_non_null_out_parameter!(string_id);
ProfileStatus::from(|| -> Result<(), ProfileError> {
let dict = dict.ok_or(NULL_PROFILES_DICTIONARY)?;
crate::profiles::utf8::insert_str(dict.strings(), byte_slice, utf8_option)
utf8::insert_str(dict.strings(), byte_slice, utf8_option)
.map(|id| unsafe { string_id.write(id.into()) })
}())
}

/// Inserts a batch of UTF-8 strings into the dictionary string table.
///
/// On success, each element of `string_ids` corresponds to the same-index element of
/// `strings`. The length of `string_ids` must equal the length of `strings`; a
/// mismatch is an error.
///
/// On failure the number of entries written to `string_ids` is unspecified; callers
/// must not read any element of `string_ids`.
///
/// # Safety
///
/// - `dict` must refer to a live dictionary.
/// - `strings` must be a valid slice for the duration of the call.
/// - `string_ids` must be a valid writable slice of `StringId2` with the same length as `strings`.
/// - The UTF-8 policy indicated by `utf8_option` must be respected by the caller for every string
/// in `strings`.
#[no_mangle]
pub unsafe extern "C" fn ddog_prof_ProfilesDictionary_insert_strs(
mut string_ids: MutSlice<StringId2>,
dict: Option<&ProfilesDictionary>,
strings: Slice<CharSlice>,
utf8_option: Utf8Option,
) -> ProfileStatus {
ProfileStatus::from(|| -> Result<(), ProfileError> {
let dict = dict.ok_or(NULL_PROFILES_DICTIONARY)?;
if strings.len() != string_ids.len() {
return Err(ProfileError::from(
c"input strings slice and output StringId2 slice have different lengths",
));
}
for (byte_slice, id_out) in strings.iter().zip(string_ids.as_mut_slice().iter_mut()) {
let id = utf8::insert_str(dict.strings(), *byte_slice, utf8_option)?;
*id_out = id.into();
}
Ok(())
}())
}

/// Tries to get the string value associated with the string id. Fails if the
/// handle has been taken from, or the result param is null.
///
Expand Down Expand Up @@ -238,6 +277,74 @@ pub unsafe extern "C" fn ddog_prof_ProfilesDictionary_drop(
mod tests {
use super::*;
use crate::profiles::utf8::Utf8Option;
use libdd_common_ffi::slice::AsBytes;

#[test]
fn test_insert_strs_success() {
let mut handle = ArcHandle::default();
unsafe {
Result::from(ddog_prof_ProfilesDictionary_new(&mut handle)).unwrap();
let dict = handle.as_inner().ok();

let inputs = ["hello", "world", "foo"];
let char_slices: Vec<CharSlice> = inputs.iter().map(|s| CharSlice::from(*s)).collect();
let mut ids = vec![StringId2::default(); inputs.len()];

Result::from(ddog_prof_ProfilesDictionary_insert_strs(
MutSlice::from(ids.as_mut_slice()),
dict,
Slice::from(char_slices.as_slice()),
Utf8Option::Validate,
))
.unwrap();

for (input, id) in inputs.iter().zip(ids.iter()) {
let mut found = CharSlice::empty();
Result::from(ddog_prof_ProfilesDictionary_get_str(&mut found, dict, *id)).unwrap();
assert_eq!(found.try_to_utf8().unwrap(), *input);
}

ddog_prof_ProfilesDictionary_drop(&mut handle);
}
}

#[test]
fn test_insert_strs_length_mismatch() {
let mut handle = ArcHandle::default();
unsafe {
Result::from(ddog_prof_ProfilesDictionary_new(&mut handle)).unwrap();
let dict = handle.as_inner().ok();

let char_slices = [CharSlice::from("a"), CharSlice::from("b")];
let mut ids = vec![StringId2::default(); 3]; // wrong length

let status = ddog_prof_ProfilesDictionary_insert_strs(
MutSlice::from(ids.as_mut_slice()),
dict,
Slice::from(char_slices.as_slice()),
Utf8Option::Validate,
);
assert!(!status.err.is_null(), "expected error for length mismatch");

ddog_prof_ProfilesDictionary_drop(&mut handle);
}
}

#[test]
fn test_insert_strs_null_dict() {
unsafe {
let char_slices = [CharSlice::from("a")];
let mut ids = vec![StringId2::default(); 1];

let status = ddog_prof_ProfilesDictionary_insert_strs(
MutSlice::from(ids.as_mut_slice()),
None,
Slice::from(char_slices.as_slice()),
Utf8Option::Validate,
);
assert!(!status.err.is_null(), "expected error for null dict");
}
}

#[test]
fn test_basics_including_drop() {
Expand Down
Loading