1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Provides a mechanism to turn an arbitrary CStr into a static. The primary
//! use is for FFIs like Perfetto which require any trace point names to be
//! static.
use std::collections::BTreeSet;
use std::ffi::CString;
use std::os::raw::c_char;
use sync::Mutex;
static STATIC_STRINGS: Mutex<BTreeSet<CString>> = Mutex::new(BTreeSet::new());
/// Holds a reference to a 'static string that was registered via `register_string`.
#[derive(Clone, Copy)]
pub struct StaticString(*const c_char);
impl StaticString {
#[inline]
pub fn as_ptr(&self) -> *const c_char {
self.0
}
/// Turns a given string into a *c_char which has static lifetime measured
/// from the moment this function returns. Registering the same string
/// multiple times behaves like interning (will not use additional
/// resources).
///
/// WARNING: this function creates data with static lifetime. It should only
/// be called on a finite set of unique strings. Using it on a non-finite
/// set will appear to be a memory leak since the space used will grow
/// without bound.
pub fn register(str: &str) -> Self {
let c_str = CString::new(str).expect("failed to convert a tracing string to a CString.");
let mut strings = STATIC_STRINGS.lock();
strings.insert(c_str.clone());
Self(strings.get(&c_str).unwrap().as_ptr())
}
}
// Safety: pointers are safe to send between threads.
unsafe impl Send for StaticString {}
// SAFETY:
// Safe to share across threads, because `register` is protected by a lock and strings inserted
// are never removed.
unsafe impl Sync for StaticString {}