diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /toolkit/components/glean/api/src/ffi | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/glean/api/src/ffi')
21 files changed, 1294 insertions, 0 deletions
diff --git a/toolkit/components/glean/api/src/ffi/boolean.rs b/toolkit/components/glean/api/src/ffi/boolean.rs new file mode 100644 index 0000000000..9184b23c00 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/boolean.rs @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_boolean_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(BOOLEAN_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_boolean_test_get_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(BOOLEAN_MAP, id, metric, test_get!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_boolean_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(BOOLEAN_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} + +#[no_mangle] +pub extern "C" fn fog_boolean_set(id: u32, value: bool) { + with_metric!(BOOLEAN_MAP, id, metric, metric.set(value)); +} diff --git a/toolkit/components/glean/api/src/ffi/counter.rs b/toolkit/components/glean/api/src/ffi/counter.rs new file mode 100644 index 0000000000..5fba7c0dea --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/counter.rs @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub unsafe extern "C" fn fog_counter_add(id: u32, amount: i32) { + with_metric!(COUNTER_MAP, id, metric, metric.add(amount)); +} + +#[no_mangle] +pub unsafe extern "C" fn fog_counter_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(COUNTER_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub unsafe extern "C" fn fog_counter_test_get_value(id: u32, ping_name: &nsACString) -> i32 { + with_metric!(COUNTER_MAP, id, metric, test_get!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_counter_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(COUNTER_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/custom_distribution.rs b/toolkit/components/glean/api/src/ffi/custom_distribution.rs new file mode 100644 index 0000000000..853a6e9845 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/custom_distribution.rs @@ -0,0 +1,82 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; +use thin_vec::ThinVec; + +#[no_mangle] +pub extern "C" fn fog_custom_distribution_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!( + CUSTOM_DISTRIBUTION_MAP, + id, + metric, + test_has!(metric, ping_name) + ) +} + +#[no_mangle] +pub extern "C" fn fog_custom_distribution_test_get_value( + id: u32, + ping_name: &nsACString, + sum: &mut u64, + buckets: &mut ThinVec<u64>, + counts: &mut ThinVec<u64>, +) { + let val = with_metric!( + CUSTOM_DISTRIBUTION_MAP, + id, + metric, + test_get!(metric, ping_name) + ); + // FIXME(bug 1771885): Glean should use `u64` where it can. + *sum = val.sum as _; + for (&bucket, &count) in val.values.iter() { + buckets.push(bucket as _); + counts.push(count as _); + } +} + +#[no_mangle] +pub extern "C" fn fog_custom_distribution_accumulate_samples(id: u32, samples: &ThinVec<u64>) { + // N.B.: Avoid reallocation here by making the underlying type take a slice. + let samples = samples.into_iter().map(|&i| i as i64).collect(); + with_metric!( + CUSTOM_DISTRIBUTION_MAP, + id, + metric, + metric.accumulate_samples_signed(samples) + ); +} + +#[no_mangle] +pub extern "C" fn fog_custom_distribution_accumulate_samples_signed( + id: u32, + samples: &ThinVec<i64>, +) { + // N.B.: Avoid reallocation here by making the underlying type take a slice. + let samples = samples.to_vec(); + with_metric!( + CUSTOM_DISTRIBUTION_MAP, + id, + metric, + metric.accumulate_samples_signed(samples) + ); +} + +#[no_mangle] +pub extern "C" fn fog_custom_distribution_test_get_error( + id: u32, + + error_str: &mut nsACString, +) -> bool { + let err = with_metric!( + CUSTOM_DISTRIBUTION_MAP, + id, + metric, + test_get_errors!(metric) + ); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/datetime.rs b/toolkit/components/glean/api/src/ffi/datetime.rs new file mode 100644 index 0000000000..7529a524e6 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/datetime.rs @@ -0,0 +1,66 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[repr(C)] +pub struct FogDatetime { + year: i32, + month: u32, + day: u32, + hour: u32, + minute: u32, + second: u32, + nano: u32, + offset_seconds: i32, +} + +#[no_mangle] +pub extern "C" fn fog_datetime_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(DATETIME_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_datetime_test_get_value( + id: u32, + ping_name: &nsACString, + value: &mut FogDatetime, +) { + let val = with_metric!(DATETIME_MAP, id, metric, test_get!(metric, ping_name)); + value.year = val.year; + value.month = val.month; + value.day = val.day; + value.hour = val.hour; + value.minute = val.minute; + value.second = val.second; + value.nano = val.nanosecond; + value.offset_seconds = val.offset_seconds; +} + +#[no_mangle] +pub extern "C" fn fog_datetime_set(id: u32, dt: &FogDatetime) { + with_metric!( + DATETIME_MAP, + id, + metric, + metric.set_with_details( + dt.year, + dt.month, + dt.day, + dt.hour, + dt.minute, + dt.second, + dt.nano, + dt.offset_seconds + ) + ); +} + +#[no_mangle] +pub extern "C" fn fog_datetime_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(DATETIME_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/denominator.rs b/toolkit/components/glean/api/src/ffi/denominator.rs new file mode 100644 index 0000000000..ccb047f530 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/denominator.rs @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub unsafe extern "C" fn fog_denominator_add(id: u32, amount: i32) { + with_metric!(DENOMINATOR_MAP, id, metric, metric.add(amount)); +} + +#[no_mangle] +pub unsafe extern "C" fn fog_denominator_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(DENOMINATOR_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub unsafe extern "C" fn fog_denominator_test_get_value(id: u32, ping_name: &nsACString) -> i32 { + with_metric!(DENOMINATOR_MAP, id, metric, test_get!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_denominator_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(DENOMINATOR_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/event.rs b/toolkit/components/glean/api/src/ffi/event.rs new file mode 100644 index 0000000000..bd167021d6 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/event.rs @@ -0,0 +1,168 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use std::collections::HashMap; + +use nsstring::{nsACString, nsCString}; +use thin_vec::ThinVec; + +use crate::metrics::__glean_metric_maps as metric_maps; +use crate::private::EventRecordingError; + +#[no_mangle] +pub extern "C" fn fog_event_record( + id: u32, + extra_keys: &ThinVec<nsCString>, + extra_values: &ThinVec<nsCString>, +) { + // If no extra keys are passed, we can shortcut here. + if extra_keys.is_empty() { + if id & (1 << crate::factory::DYNAMIC_METRIC_BIT) > 0 { + let map = crate::factory::__jog_metric_maps::EVENT_MAP + .read() + .expect("Read lock for dynamic metric map was poisoned"); + match map.get(&id.into()) { + Some(m) => m.record_raw(Default::default()), + None => panic!("No (dynamic) metric for event with id {}", id), + } + return; + } + + if metric_maps::record_event_by_id(id, Default::default()).is_err() { + panic!("No event for id {}", id); + } + + return; + } + + assert_eq!( + extra_keys.len(), + extra_values.len(), + "Extra keys and values differ in length. ID: {}", + id + ); + + // Otherwise we need to decode them and pass them along. + let extra = extra_keys + .iter() + .zip(extra_values.iter()) + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); + if id & (1 << crate::factory::DYNAMIC_METRIC_BIT) > 0 { + let map = crate::factory::__jog_metric_maps::EVENT_MAP + .read() + .expect("Read lock for dynamic metric map was poisoned"); + match map.get(&id.into()) { + Some(m) => m.record_raw(extra), + None => panic!("No (dynamic) metric for event with id {}", id), + } + return; + } else { + match metric_maps::record_event_by_id(id, extra) { + Ok(()) => {} + Err(EventRecordingError::InvalidId) => panic!("No event for id {}", id), + Err(_) => panic!("Unpossible!"), + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn fog_event_test_has_value(id: u32, ping_name: &nsACString) -> bool { + let storage = if ping_name.is_empty() { + None + } else { + Some(ping_name.to_utf8().into_owned()) + }; + if id & (1 << crate::factory::DYNAMIC_METRIC_BIT) > 0 { + let map = crate::factory::__jog_metric_maps::EVENT_MAP + .read() + .expect("Read lock for dynamic metric map was poisoned"); + match map.get(&id.into()) { + Some(m) => m.test_get_value(storage.as_deref()).is_some(), + None => panic!("No (dynamic) metric for event with id {}", id), + } + } else { + metric_maps::event_test_get_value_wrapper(id, storage).is_some() + } +} + +#[no_mangle] +pub extern "C" fn fog_event_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = if id & (1 << crate::factory::DYNAMIC_METRIC_BIT) > 0 { + let map = crate::factory::__jog_metric_maps::EVENT_MAP + .read() + .expect("Read lock for dynamic metric map was poisoned"); + match map.get(&id.into()) { + Some(m) => test_get_errors!(m), + None => panic!("No (dynamic) metric for event with id {}", id), + } + } else { + metric_maps::event_test_get_error(id) + }; + err.map(|err_str| error_str.assign(&err_str)).is_some() +} + +/// FFI-compatible representation of recorded event data. +#[repr(C)] +pub struct FfiRecordedEvent { + timestamp: u64, + category: nsCString, + name: nsCString, + + /// Array of extra data, keys and values are interleaved. + extras: ThinVec<nsCString>, +} + +#[no_mangle] +pub extern "C" fn fog_event_test_get_value( + id: u32, + ping_name: &nsACString, + out_events: &mut ThinVec<FfiRecordedEvent>, +) { + let storage = if ping_name.is_empty() { + None + } else { + Some(ping_name.to_utf8().into_owned()) + }; + + let events = if id & (1 << crate::factory::DYNAMIC_METRIC_BIT) > 0 { + let map = crate::factory::__jog_metric_maps::EVENT_MAP + .read() + .expect("Read lock for dynamic metric map was poisoned"); + let events = match map.get(&id.into()) { + Some(m) => m.test_get_value(storage.as_deref()), + None => return, + }; + match events { + Some(events) => events, + None => return, + } + } else { + match metric_maps::event_test_get_value_wrapper(id, storage) { + Some(events) => events, + None => return, + } + }; + + for event in events { + let extra = event.extra.unwrap_or_else(HashMap::new); + let extra_len = extra.len(); + let mut extras = ThinVec::with_capacity(extra_len * 2); + for (k, v) in extra.into_iter() { + extras.push(nsCString::from(k)); + extras.push(nsCString::from(v)); + } + + let event = FfiRecordedEvent { + timestamp: event.timestamp, + category: nsCString::from(event.category), + name: nsCString::from(event.name), + extras, + }; + + out_events.push(event); + } +} diff --git a/toolkit/components/glean/api/src/ffi/labeled.rs b/toolkit/components/glean/api/src/ffi/labeled.rs new file mode 100644 index 0000000000..2cd61230f7 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/labeled.rs @@ -0,0 +1,84 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use crate::metrics::__glean_metric_maps as metric_maps; +use nsstring::nsACString; +use std::sync::atomic::Ordering; + +#[no_mangle] +pub extern "C" fn fog_labeled_enum_to_str(id: u32, label: u16, value: &mut nsACString) { + let val = metric_maps::labeled_enum_to_str(id, label); + value.assign(&val); +} + +#[no_mangle] +pub extern "C" fn fog_labeled_boolean_get(id: u32, label: &nsACString) -> u32 { + labeled_submetric_get!( + id, + label, + LABELED_BOOLEAN_MAP, + labeled_boolean_get, + BOOLEAN_MAP, + LabeledBooleanMetric + ) +} + +#[no_mangle] +pub extern "C" fn fog_labeled_boolean_enum_get(id: u32, label: u16) -> u32 { + labeled_submetric_enum_get!( + id, + label, + labeled_boolean_enum_get, + BOOLEAN_MAP, + LabeledBooleanMetric + ) +} + +#[no_mangle] +pub extern "C" fn fog_labeled_counter_get(id: u32, label: &nsACString) -> u32 { + labeled_submetric_get!( + id, + label, + LABELED_COUNTER_MAP, + labeled_counter_get, + COUNTER_MAP, + LabeledCounterMetric + ) +} + +#[no_mangle] +pub extern "C" fn fog_labeled_counter_enum_get(id: u32, label: u16) -> u32 { + labeled_submetric_enum_get!( + id, + label, + labeled_counter_enum_get, + COUNTER_MAP, + LabeledCounterMetric + ) +} + +#[no_mangle] +pub extern "C" fn fog_labeled_string_get(id: u32, label: &nsACString) -> u32 { + labeled_submetric_get!( + id, + label, + LABELED_STRING_MAP, + labeled_string_get, + STRING_MAP, + LabeledStringMetric + ) +} + +#[no_mangle] +pub extern "C" fn fog_labeled_string_enum_get(id: u32, label: u16) -> u32 { + labeled_submetric_enum_get!( + id, + label, + labeled_string_enum_get, + STRING_MAP, + LabeledStringMetric + ) +} diff --git a/toolkit/components/glean/api/src/ffi/macros.rs b/toolkit/components/glean/api/src/ffi/macros.rs new file mode 100644 index 0000000000..3571ebd88b --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/macros.rs @@ -0,0 +1,289 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Helper macros for implementing the FFI API for metric types. + +/// Get a metric object by ID from the corresponding map, then +/// execute the provided closure with it. +/// +/// # Arguments +/// +/// * `$map` - The name of the hash map within `metrics::__glean_metric_maps` +/// (or `factory::__jog_metric_maps`) +/// as generated by glean_parser. +/// * `$id` - The ID of the metric to get. +/// * `$m` - The identifier to use for the retrieved metric. +/// The expression `$f` can use this identifier. +/// * `$f` - The expression to execute with the retrieved metric `$m`. +macro_rules! with_metric { + (BOOLEAN_MAP, $id:ident, $m:ident, $f:expr) => { + maybe_labeled_with_metric!(BOOLEAN_MAP, $id, $m, $f) + }; + (COUNTER_MAP, $id:ident, $m:ident, $f:expr) => { + maybe_labeled_with_metric!(COUNTER_MAP, $id, $m, $f) + }; + (STRING_MAP, $id:ident, $m:ident, $f:expr) => { + maybe_labeled_with_metric!(STRING_MAP, $id, $m, $f) + }; + ($map:ident, $id:ident, $m:ident, $f:expr) => { + just_with_metric!($map, $id, $m, $f) + }; +} + +/// Get a dynamically-registered metric object by id from the corresponding map, +/// then execute the provided closure with it. +/// +/// Assumes `$id` is for a dynamic non-submetric metric. +/// Will panic if it isn't. +/// +/// # Arguments +/// +/// * `$map` - The name of the hash map within `factory::__jog_metric_maps` +/// as generated by glean_parser. +/// * `$id` - The ID of the metric to get. +/// * `$m` - The identifier to use for the retrieved metric. +/// The expression `$f` can use this identifier. +/// * `$f` - The expression to execute with the retrieved metric `$m`. +macro_rules! just_with_jog_metric { + ($map:ident, $id:ident, $m:ident, $f:expr) => {{ + let map = $crate::factory::__jog_metric_maps::$map + .read() + .expect("Read lock for dynamic metric map was poisoned"); + match map.get(&$id.into()) { + Some($m) => $f, + None => panic!("No (dynamic) metric for id {}", $id), + } + }}; +} + +/// Get a metric object by id from the corresponding map, then +/// execute the provided closure with it. +/// +/// Ignores the possibility that the $id might be for a labeled submetric. +/// +/// # Arguments +/// +/// * `$map` - The name of the hash map within `metrics::__glean_metric_maps` +/// (or `factory::__jog_metric_maps`) +/// as generated by glean_parser. +/// * `$id` - The ID of the metric to get. +/// * `$m` - The identifier to use for the retrieved metric. +/// The expression `$f` can use this identifier. +/// * `$f` - The expression to execute with the retrieved metric `$m`. +macro_rules! just_with_metric { + ($map:ident, $id:ident, $m:ident, $f:expr) => { + if $id & (1 << $crate::factory::DYNAMIC_METRIC_BIT) > 0 { + just_with_jog_metric!($map, $id, $m, $f) + } else { + match $crate::metrics::__glean_metric_maps::$map.get(&$id.into()) { + Some($m) => $f, + None => panic!("No metric for id {}", $id), + } + } + }; +} + +/// Get a metric object by id from the corresponding map, then +/// execute the provided closure with it. +/// +/// Requires that the provided $map be of a type that can be labeled, since it +/// assumes the presence of a same-named map in +/// `metrics::_glean_metrics_map::submetric_maps`. +/// +/// # Arguments +/// +/// * `$map` - The name of the hash map within `metrics::__glean_metric_maps` +/// and `metrics::__glean_metric_maps::submetric_maps` as generated +/// by glean_parser. +/// * `$id` - The ID of the metric to get. +/// * `$m` - The identifier to use for the retrieved metric. +/// The expression `$f` can use this identifier. +/// * `$f` - The expression to execute with the retrieved metric `$m`. +macro_rules! maybe_labeled_with_metric { + ($map:ident, $id:ident, $m:ident, $f:expr) => { + if $id & (1 << $crate::metrics::__glean_metric_maps::submetric_maps::SUBMETRIC_BIT) > 0 { + let map = $crate::metrics::__glean_metric_maps::submetric_maps::$map + .read() + .expect("Read lock for labeled metric map was poisoned"); + match map.get(&$id.into()) { + Some($m) => $f, + None => panic!("No submetric for id {}", $id), + } + } else { + just_with_metric!($map, $id, $m, $f) + } + }; +} + +/// Test whether a value is stored for the given metric. +/// +/// # Arguments +/// +/// * `$metric` - The metric to test. +/// * `$storage` - the storage name to look into. +macro_rules! test_has { + ($metric:ident, $storage:ident) => {{ + let storage = if $storage.is_empty() { + None + } else { + Some($storage.to_utf8()) + }; + $metric.test_get_value(storage.as_deref()).is_some() + }}; +} + +/// Get the currently stored value for the given metric. +/// +/// # Arguments +/// +/// * `$metric` - The metric to test. +/// * `$storage` - the storage name to look into. +macro_rules! test_get { + ($metric:ident, $storage:ident) => {{ + let storage = if $storage.is_empty() { + None + } else { + Some($storage.to_utf8()) + }; + $metric.test_get_value(storage.as_deref()).unwrap() + }}; +} + +/// Check the provided metric in the provided storage for errors. +/// On finding one, return an error string. +/// +/// # Arguments +/// +/// * `$metric` - The metric to test. +macro_rules! test_get_errors { + ($metric:path) => {{ + let error_types = [ + glean::ErrorType::InvalidValue, + glean::ErrorType::InvalidLabel, + glean::ErrorType::InvalidState, + glean::ErrorType::InvalidOverflow, + ]; + let mut error_str = None; + for &error_type in error_types.iter() { + let num_errors = $metric.test_get_num_recorded_errors(error_type); + if num_errors > 0 { + error_str = Some(format!( + "Metric had {} error(s) of type {}!", + num_errors, + error_type.as_str() + )); + break; + } + } + error_str + }}; +} + +/// Get the submetric id for a given labeled metric and label. +/// +/// # Arguments +/// +/// * `$id` - The id of the labeled metric. +/// * `$label` - The (string) label of the submetric. +/// * `$labeled_map` - The name of the labeled metric's map for retrieval (JOG only). +/// * `$labeled_get` - The name of the labeled metric's get fn for retrieval. +/// * `$submetric_map`- The name of the submetrics' map for storage. +/// * `$metric_type` - The submetric's type (needed for an internal closure). +macro_rules! labeled_submetric_get { + ($id:ident, $label:ident, $labeled_map:ident, $labeled_get:ident, $submetric_map:ident, $metric_type:ty) => {{ + let tuple = ($id, $label.to_utf8().into()); + { + let map = $crate::metrics::__glean_metric_maps::submetric_maps::LABELED_METRICS_TO_IDS + .read() + .expect("read lock of submetric ids was poisoned"); + if let Some(submetric_id) = map.get(&tuple) { + return *submetric_id; + } + } + + // Gotta actually create a new submetric with a new id. + let submetric_id = + $crate::metrics::__glean_metric_maps::submetric_maps::NEXT_LABELED_SUBMETRIC_ID + .fetch_add(1, Ordering::SeqCst); + { + if $id & (1 << $crate::factory::DYNAMIC_METRIC_BIT) > 0 { + just_with_jog_metric!($labeled_map, $id, metric, { + let submetric = metric.get(&tuple.1); + let mut map = + $crate::metrics::__glean_metric_maps::submetric_maps::$submetric_map + .write() + .expect("write lock of submetric map was poisoned"); + map.insert(submetric_id.into(), submetric); + }); + } else { + let mut map = $crate::metrics::__glean_metric_maps::submetric_maps::$submetric_map + .write() + .expect("write lock of submetric map was poisoned"); + map.insert( + submetric_id.into(), + $crate::metrics::__glean_metric_maps::$labeled_get($id, &tuple.1), + ); + } + } + + let mut map = $crate::metrics::__glean_metric_maps::submetric_maps::LABELED_METRICS_TO_IDS + .write() + .expect("write lock of submetric ids was poisoned"); + map.insert(tuple, submetric_id); + submetric_id + }}; +} + +/// Get the submetric id for a given labeled metric and label enum. +/// +/// # Arguments +/// +/// * `$id` - The id of the labeled metric. +/// * `$label` - The (enum) label of the submetric. +/// * `$labeled_get` - The name of the labeled metric's get fn for retrieval. +/// * `$submetric_map`- The name of the submetrics' map for storage. +/// * `$metric_type` - The submetric's type (needed for an internal closure). +macro_rules! labeled_submetric_enum_get { + ($id:ident, $label_enum:ident, $labeled_get:ident, $submetric_map:ident, $metric_type:ty) => {{ + let tuple = ($id, $label_enum.into()); + // First: Have we seen this enum before? If so, give out the same submetric id. + { + let map = $crate::metrics::__glean_metric_maps::submetric_maps::LABELED_ENUMS_TO_IDS + .read() + .expect("read lock of enum submetric ids was poisoned"); + if let Some(submetric_id) = map.get(&tuple) { + return *submetric_id; + } + } + + // Alas, this is the first time we've needed to handle this metric with this enum. + // Gotta actually create a new submetric with a new id. + let submetric_id = + $crate::metrics::__glean_metric_maps::submetric_maps::NEXT_LABELED_SUBMETRIC_ID + .fetch_add(1, Ordering::SeqCst); + { + // What if the dynamic bit is set? + // JOG only supports JS, and enum_get isn't (yet) supported in JS. + assert_eq!( + 0, + $id & (1 << $crate::factory::DYNAMIC_METRIC_BIT), + "No enum_get support for JOG" + ); + let mut map = $crate::metrics::__glean_metric_maps::submetric_maps::$submetric_map + .write() + .expect("write lock of submetric map was poisoned"); + map.insert( + submetric_id.into(), + $crate::metrics::__glean_metric_maps::$labeled_get($id, tuple.1), + ); + } + + // And now ensure we store the submetric so we need not create it on subsequent calls. + let mut map = $crate::metrics::__glean_metric_maps::submetric_maps::LABELED_ENUMS_TO_IDS + .write() + .expect("write lock of submetric ids was poisoned"); + map.insert(tuple, submetric_id); + submetric_id + }}; +} diff --git a/toolkit/components/glean/api/src/ffi/memory_distribution.rs b/toolkit/components/glean/api/src/ffi/memory_distribution.rs new file mode 100644 index 0000000000..cf09d3f8de --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/memory_distribution.rs @@ -0,0 +1,64 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; +use thin_vec::ThinVec; + +#[no_mangle] +pub extern "C" fn fog_memory_distribution_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!( + MEMORY_DISTRIBUTION_MAP, + id, + metric, + test_has!(metric, ping_name) + ) +} + +#[no_mangle] +pub extern "C" fn fog_memory_distribution_test_get_value( + id: u32, + ping_name: &nsACString, + sum: &mut u64, + buckets: &mut ThinVec<u64>, + counts: &mut ThinVec<u64>, +) { + let val = with_metric!( + MEMORY_DISTRIBUTION_MAP, + id, + metric, + test_get!(metric, ping_name) + ); + *sum = val.sum as _; + for (&bucket, &count) in val.values.iter() { + buckets.push(bucket as _); + counts.push(count as _); + } +} + +#[no_mangle] +pub extern "C" fn fog_memory_distribution_accumulate(id: u32, sample: u64) { + with_metric!( + MEMORY_DISTRIBUTION_MAP, + id, + metric, + metric.accumulate(sample) + ); +} + +#[no_mangle] +pub extern "C" fn fog_memory_distribution_test_get_error( + id: u32, + + error_str: &mut nsACString, +) -> bool { + let err = with_metric!( + MEMORY_DISTRIBUTION_MAP, + id, + metric, + test_get_errors!(metric) + ); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/mod.rs b/toolkit/components/glean/api/src/ffi/mod.rs new file mode 100644 index 0000000000..23235fc2f1 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/mod.rs @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +#[macro_use] +mod macros; + +mod boolean; +mod counter; +mod custom_distribution; +mod datetime; +mod denominator; +mod event; +mod labeled; +mod memory_distribution; +mod numerator; +mod ping; +mod quantity; +mod rate; +mod string; +mod string_list; +mod text; +mod timespan; +mod timing_distribution; +mod url; +mod uuid; diff --git a/toolkit/components/glean/api/src/ffi/numerator.rs b/toolkit/components/glean/api/src/ffi/numerator.rs new file mode 100644 index 0000000000..e679e426c4 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/numerator.rs @@ -0,0 +1,35 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub unsafe extern "C" fn fog_numerator_add_to_numerator(id: u32, amount: i32) { + with_metric!(NUMERATOR_MAP, id, metric, metric.add_to_numerator(amount)); +} + +#[no_mangle] +pub unsafe extern "C" fn fog_numerator_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(NUMERATOR_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub unsafe extern "C" fn fog_numerator_test_get_value( + id: u32, + ping_name: &nsACString, + num: &mut i32, + den: &mut i32, +) { + let rate = with_metric!(NUMERATOR_MAP, id, metric, test_get!(metric, ping_name)); + *num = rate.numerator; + *den = rate.denominator; +} + +#[no_mangle] +pub extern "C" fn fog_numerator_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(NUMERATOR_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/ping.rs b/toolkit/components/glean/api/src/ffi/ping.rs new file mode 100644 index 0000000000..2834655a03 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/ping.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use crate::pings; +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_submit_ping_by_id(id: u32, reason: &nsACString) { + let reason = if reason.is_empty() { + None + } else { + Some(reason.to_utf8()) + }; + pings::submit_ping_by_id(id, reason.as_deref()); +} diff --git a/toolkit/components/glean/api/src/ffi/quantity.rs b/toolkit/components/glean/api/src/ffi/quantity.rs new file mode 100644 index 0000000000..7f94bcff27 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/quantity.rs @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_quantity_set(id: u32, value: i64) { + with_metric!(QUANTITY_MAP, id, metric, metric.set(value)); +} + +#[no_mangle] +pub extern "C" fn fog_quantity_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(QUANTITY_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_quantity_test_get_value(id: u32, ping_name: &nsACString) -> i64 { + with_metric!(QUANTITY_MAP, id, metric, test_get!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_quantity_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(QUANTITY_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/rate.rs b/toolkit/components/glean/api/src/ffi/rate.rs new file mode 100644 index 0000000000..c14b33f3ea --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/rate.rs @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub unsafe extern "C" fn fog_rate_add_to_numerator(id: u32, amount: i32) { + with_metric!(RATE_MAP, id, metric, metric.add_to_numerator(amount)); +} + +#[no_mangle] +pub unsafe extern "C" fn fog_rate_add_to_denominator(id: u32, amount: i32) { + with_metric!(RATE_MAP, id, metric, metric.add_to_denominator(amount)); +} + +#[no_mangle] +pub unsafe extern "C" fn fog_rate_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(RATE_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub unsafe extern "C" fn fog_rate_test_get_value( + id: u32, + ping_name: &nsACString, + num: &mut i32, + den: &mut i32, +) { + let rate = with_metric!(RATE_MAP, id, metric, test_get!(metric, ping_name)); + *num = rate.numerator; + *den = rate.denominator; +} + +#[no_mangle] +pub extern "C" fn fog_rate_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(RATE_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/string.rs b/toolkit/components/glean/api/src/ffi/string.rs new file mode 100644 index 0000000000..fc28e03a38 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/string.rs @@ -0,0 +1,33 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_string_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(STRING_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_string_test_get_value( + id: u32, + ping_name: &nsACString, + value: &mut nsACString, +) { + let val = with_metric!(STRING_MAP, id, metric, test_get!(metric, ping_name)); + value.assign(&val); +} + +#[no_mangle] +pub extern "C" fn fog_string_set(id: u32, value: &nsACString) { + with_metric!(STRING_MAP, id, metric, metric.set(value.to_utf8())); +} + +#[no_mangle] +pub extern "C" fn fog_string_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(STRING_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/string_list.rs b/toolkit/components/glean/api/src/ffi/string_list.rs new file mode 100644 index 0000000000..42ebd9e445 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/string_list.rs @@ -0,0 +1,42 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::{nsACString, nsCString}; +use thin_vec::ThinVec; + +#[no_mangle] +pub extern "C" fn fog_string_list_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(STRING_LIST_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_string_list_test_get_value( + id: u32, + ping_name: &nsACString, + value: &mut ThinVec<nsCString>, +) { + let val = with_metric!(STRING_LIST_MAP, id, metric, test_get!(metric, ping_name)); + for v in val { + value.push(v.into()); + } +} + +#[no_mangle] +pub extern "C" fn fog_string_list_add(id: u32, value: &nsACString) { + with_metric!(STRING_LIST_MAP, id, metric, metric.add(value.to_utf8())); +} + +#[no_mangle] +pub extern "C" fn fog_string_list_set(id: u32, value: &ThinVec<nsCString>) { + let value = value.iter().map(|s| s.to_utf8().into()).collect(); + with_metric!(STRING_LIST_MAP, id, metric, metric.set(value)); +} + +#[no_mangle] +pub extern "C" fn fog_string_list_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(STRING_LIST_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/text.rs b/toolkit/components/glean/api/src/ffi/text.rs new file mode 100644 index 0000000000..da46fb849f --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/text.rs @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_text_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(TEXT_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_text_test_get_value(id: u32, ping_name: &nsACString, value: &mut nsACString) { + let val = with_metric!(TEXT_MAP, id, metric, test_get!(metric, ping_name)); + value.assign(&val); +} + +#[no_mangle] +pub extern "C" fn fog_text_set(id: u32, value: &nsACString) { + with_metric!(TEXT_MAP, id, metric, metric.set(value.to_utf8())); +} + +#[no_mangle] +pub extern "C" fn fog_text_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(TEXT_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/timespan.rs b/toolkit/components/glean/api/src/ffi/timespan.rs new file mode 100644 index 0000000000..5de411ffab --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/timespan.rs @@ -0,0 +1,48 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_timespan_start(id: u32) { + with_metric!(TIMESPAN_MAP, id, metric, metric.start()); +} + +#[no_mangle] +pub extern "C" fn fog_timespan_stop(id: u32) { + with_metric!(TIMESPAN_MAP, id, metric, metric.stop()); +} + +#[no_mangle] +pub extern "C" fn fog_timespan_cancel(id: u32) { + with_metric!(TIMESPAN_MAP, id, metric, metric.cancel()); +} + +#[no_mangle] +pub extern "C" fn fog_timespan_set_raw(id: u32, duration: u32) { + with_metric!( + TIMESPAN_MAP, + id, + metric, + metric.set_raw_unitless(duration.into()) + ); +} + +#[no_mangle] +pub extern "C" fn fog_timespan_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(TIMESPAN_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_timespan_test_get_value(id: u32, ping_name: &nsACString) -> u64 { + with_metric!(TIMESPAN_MAP, id, metric, test_get!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_timespan_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(TIMESPAN_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/timing_distribution.rs b/toolkit/components/glean/api/src/ffi/timing_distribution.rs new file mode 100644 index 0000000000..4ac5d03986 --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/timing_distribution.rs @@ -0,0 +1,90 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; +use std::time::Duration; +use thin_vec::ThinVec; + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_start(id: u32) -> u64 { + with_metric!(TIMING_DISTRIBUTION_MAP, id, metric, metric.start().id) +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_stop_and_accumulate(id: u32, timing_id: u64) { + with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + metric.stop_and_accumulate(timing_id.into()) + ); +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_accumulate_raw_nanos(id: u32, sample: u64) { + with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + metric.accumulate_raw_duration(Duration::from_nanos(sample)) + ); +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_cancel(id: u32, timing_id: u64) { + with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + metric.cancel(timing_id.into()) + ); +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + test_has!(metric, ping_name) + ) +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_test_get_value( + id: u32, + ping_name: &nsACString, + sum: &mut u64, + buckets: &mut ThinVec<u64>, + counts: &mut ThinVec<u64>, +) { + let val = with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + test_get!(metric, ping_name) + ); + *sum = val.sum as _; + for (&bucket, &count) in val.values.iter() { + buckets.push(bucket as _); + counts.push(count as _); + } +} + +#[no_mangle] +pub extern "C" fn fog_timing_distribution_test_get_error( + id: u32, + + error_str: &mut nsACString, +) -> bool { + let err = with_metric!( + TIMING_DISTRIBUTION_MAP, + id, + metric, + test_get_errors!(metric) + ); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/url.rs b/toolkit/components/glean/api/src/ffi/url.rs new file mode 100644 index 0000000000..b94915f7cf --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/url.rs @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; + +#[no_mangle] +pub extern "C" fn fog_url_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(URL_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_url_test_get_value(id: u32, ping_name: &nsACString, value: &mut nsACString) { + let val = with_metric!(URL_MAP, id, metric, test_get!(metric, ping_name)); + value.assign(&val); +} + +#[no_mangle] +pub extern "C" fn fog_url_set(id: u32, value: &nsACString) { + with_metric!(URL_MAP, id, metric, metric.set(value.to_utf8())); +} + +#[no_mangle] +pub extern "C" fn fog_url_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(URL_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} diff --git a/toolkit/components/glean/api/src/ffi/uuid.rs b/toolkit/components/glean/api/src/ffi/uuid.rs new file mode 100644 index 0000000000..e3101863ea --- /dev/null +++ b/toolkit/components/glean/api/src/ffi/uuid.rs @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![cfg(feature = "with_gecko")] + +use nsstring::nsACString; +use uuid::Uuid; + +#[no_mangle] +pub extern "C" fn fog_uuid_test_has_value(id: u32, ping_name: &nsACString) -> bool { + with_metric!(UUID_MAP, id, metric, test_has!(metric, ping_name)) +} + +#[no_mangle] +pub extern "C" fn fog_uuid_test_get_value(id: u32, ping_name: &nsACString, value: &mut nsACString) { + let uuid = with_metric!(UUID_MAP, id, metric, test_get!(metric, ping_name)).to_string(); + value.assign(&uuid); +} + +#[no_mangle] +pub extern "C" fn fog_uuid_set(id: u32, value: &nsACString) { + if let Ok(uuid) = Uuid::parse_str(&value.to_utf8()) { + with_metric!(UUID_MAP, id, metric, metric.set(uuid)); + } +} + +#[no_mangle] +pub extern "C" fn fog_uuid_generate_and_set(id: u32) { + with_metric!(UUID_MAP, id, metric, metric.generate_and_set()); +} + +#[no_mangle] +pub extern "C" fn fog_uuid_test_get_error(id: u32, error_str: &mut nsACString) -> bool { + let err = with_metric!(UUID_MAP, id, metric, test_get_errors!(metric)); + err.map(|err_str| error_str.assign(&err_str)).is_some() +} |