#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CxxLibHeader {
New,
TypeInfo,
InitializerList,
Utility,
TypeTraits,
Tuple,
Functional,
}
impl CxxLibHeader {
pub fn filename(&self) -> &'static str {
match self {
CxxLibHeader::New => "<new>",
CxxLibHeader::TypeInfo => "<typeinfo>",
CxxLibHeader::InitializerList => "<initializer_list>",
CxxLibHeader::Utility => "<utility>",
CxxLibHeader::TypeTraits => "<type_traits>",
CxxLibHeader::Tuple => "<tuple>",
CxxLibHeader::Functional => "<functional>",
}
}
pub fn name(&self) -> &'static str {
match self {
CxxLibHeader::New => "new",
CxxLibHeader::TypeInfo => "typeinfo",
CxxLibHeader::InitializerList => "initializer_list",
CxxLibHeader::Utility => "utility",
CxxLibHeader::TypeTraits => "type_traits",
CxxLibHeader::Tuple => "tuple",
CxxLibHeader::Functional => "functional",
}
}
pub fn all() -> &'static [CxxLibHeader] {
&[
CxxLibHeader::New,
CxxLibHeader::TypeInfo,
CxxLibHeader::InitializerList,
CxxLibHeader::Utility,
CxxLibHeader::TypeTraits,
CxxLibHeader::Tuple,
CxxLibHeader::Functional,
]
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CxxLibType {
Void,
Bool,
Char,
Int,
UInt,
Long,
ULong,
LongLong,
ULongLong,
SizeT,
PtrDiffT,
NullptrT,
VoidPtr,
ConstVoidPtr,
CharPtr,
ConstCharPtr,
TypeParam {
index: usize,
},
Pointer {
elem: Box<CxxLibType>,
},
Reference {
elem: Box<CxxLibType>,
},
RvalueRef {
elem: Box<CxxLibType>,
},
TypeInfoRef,
InitializerList {
elem: Box<CxxLibType>,
},
Pair {
first: Box<CxxLibType>,
second: Box<CxxLibType>,
},
Tuple {
elements: Vec<CxxLibType>,
},
Function {
ret: Box<CxxLibType>,
args: Vec<CxxLibType>,
},
ReferenceWrapper {
elem: Box<CxxLibType>,
},
Hash {
elem: Box<CxxLibType>,
},
IntegralConstant {
ty: Box<CxxLibType>,
value: i64,
},
FnPtr {
ret: Box<CxxLibType>,
params: Vec<CxxLibType>,
},
}
impl CxxLibType {
pub fn as_str(&self) -> String {
match self {
CxxLibType::Void => "void".into(),
CxxLibType::Bool => "bool".into(),
CxxLibType::Char => "char".into(),
CxxLibType::Int => "int".into(),
CxxLibType::UInt => "unsigned int".into(),
CxxLibType::Long => "long".into(),
CxxLibType::ULong => "unsigned long".into(),
CxxLibType::LongLong => "long long".into(),
CxxLibType::ULongLong => "unsigned long long".into(),
CxxLibType::SizeT => "size_t".into(),
CxxLibType::PtrDiffT => "ptrdiff_t".into(),
CxxLibType::NullptrT => "nullptr_t".into(),
CxxLibType::VoidPtr => "void*".into(),
CxxLibType::ConstVoidPtr => "const void*".into(),
CxxLibType::CharPtr => "char*".into(),
CxxLibType::ConstCharPtr => "const char*".into(),
CxxLibType::TypeParam { index } => format!("T{}", index),
CxxLibType::Pointer { ref elem } => format!("{}*", elem.as_str()),
CxxLibType::Reference { ref elem } => format!("{}&", elem.as_str()),
CxxLibType::RvalueRef { ref elem } => format!("{}&&", elem.as_str()),
CxxLibType::TypeInfoRef => "const std::type_info&".into(),
CxxLibType::InitializerList { ref elem } => {
format!("std::initializer_list<{}>", elem.as_str())
}
CxxLibType::Pair {
ref first,
ref second,
} => format!("std::pair<{}, {}>", first.as_str(), second.as_str()),
CxxLibType::Tuple { ref elements } => {
let elems: Vec<String> = elements.iter().map(|e| e.as_str()).collect();
format!("std::tuple<{}>", elems.join(", "))
}
CxxLibType::Function { ref ret, ref args } => {
let args_s: Vec<String> = args.iter().map(|a| a.as_str()).collect();
format!("std::function<{}({})>", ret.as_str(), args_s.join(", "))
}
CxxLibType::ReferenceWrapper { ref elem } => {
format!("std::reference_wrapper<{}>", elem.as_str())
}
CxxLibType::Hash { ref elem } => format!("std::hash<{}>", elem.as_str()),
CxxLibType::IntegralConstant { ref ty, value } => {
format!("std::integral_constant<{}, {}>", ty.as_str(), value)
}
CxxLibType::FnPtr {
ref ret,
ref params,
} => {
let ps: Vec<String> = params.iter().map(|p| p.as_str()).collect();
format!("{}(*)({})", ret.as_str(), ps.join(", "))
}
}
}
pub fn is_pointer(&self) -> bool {
matches!(
self,
CxxLibType::Pointer { .. }
| CxxLibType::VoidPtr
| CxxLibType::CharPtr
| CxxLibType::ConstCharPtr
| CxxLibType::ConstVoidPtr
)
}
pub fn is_reference(&self) -> bool {
matches!(
self,
CxxLibType::Reference { .. } | CxxLibType::RvalueRef { .. }
)
}
pub fn type_param(index: usize) -> Self {
CxxLibType::TypeParam { index }
}
}
impl std::fmt::Display for CxxLibType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CxxLibEntityCategory {
MemoryManagement,
TypeInfo,
Utility,
TypeTraits,
TupleOps,
FunctionOps,
}
#[derive(Debug, Clone)]
pub struct CxxLibFunction {
pub name: String,
pub header: CxxLibHeader,
pub ret_ty: CxxLibType,
pub params: Vec<CxxLibType>,
pub is_variadic: bool,
pub category: CxxLibEntityCategory,
pub is_noexcept: bool,
pub is_constexpr: bool,
pub doc: &'static str,
}
impl CxxLibFunction {
pub fn new(
name: &str,
header: CxxLibHeader,
ret_ty: CxxLibType,
params: Vec<CxxLibType>,
category: CxxLibEntityCategory,
doc: &'static str,
) -> Self {
CxxLibFunction {
name: name.to_string(),
header,
ret_ty,
params,
is_variadic: false,
category,
is_noexcept: false,
is_constexpr: false,
doc,
}
}
pub fn with_noexcept(mut self) -> Self {
self.is_noexcept = true;
self
}
pub fn with_constexpr(mut self) -> Self {
self.is_constexpr = true;
self
}
}
#[derive(Debug, Clone)]
pub struct CxxTypeTrait {
pub name: String,
pub header: CxxLibHeader,
pub template_params: usize,
pub doc: &'static str,
}
impl CxxTypeTrait {
pub fn new(name: &str, template_params: usize, doc: &'static str) -> Self {
CxxTypeTrait {
name: name.to_string(),
header: CxxLibHeader::TypeTraits,
template_params,
doc,
}
}
}
#[derive(Debug, Clone)]
pub struct CxxLibClass {
pub name: String,
pub header: CxxLibHeader,
pub template_params: usize,
pub methods: Vec<String>,
pub base_classes: Vec<String>,
pub doc: &'static str,
}
impl CxxLibClass {
pub fn new(
name: &str,
header: CxxLibHeader,
template_params: usize,
doc: &'static str,
) -> Self {
CxxLibClass {
name: name.to_string(),
header,
template_params,
methods: vec![],
base_classes: vec![],
doc,
}
}
pub fn with_methods(mut self, methods: Vec<&str>) -> Self {
self.methods = methods.into_iter().map(|s| s.to_string()).collect();
self
}
pub fn with_bases(mut self, bases: Vec<&str>) -> Self {
self.base_classes = bases.into_iter().map(|s| s.to_string()).collect();
self
}
}
#[derive(Debug, Clone)]
pub struct CxxLibConstant {
pub name: String,
pub header: CxxLibHeader,
pub value: String,
pub doc: &'static str,
}
impl CxxLibConstant {
pub fn new(name: &str, header: CxxLibHeader, value: &str, doc: &'static str) -> Self {
CxxLibConstant {
name: name.to_string(),
header,
value: value.to_string(),
doc,
}
}
}
fn build_new_functions() -> Vec<CxxLibFunction> {
vec![
CxxLibFunction::new(
"operator new",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![CxxLibType::SizeT],
CxxLibEntityCategory::MemoryManagement,
"Allocates size bytes of storage. Throws std::bad_alloc on failure.",
),
CxxLibFunction::new(
"operator new[]",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![CxxLibType::SizeT],
CxxLibEntityCategory::MemoryManagement,
"Allocates storage for an array of objects. Throws std::bad_alloc on failure.",
),
CxxLibFunction::new(
"operator new",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![
CxxLibType::SizeT,
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeInfoRef),
},
],
CxxLibEntityCategory::MemoryManagement,
"Allocates storage with alignment. (C++17 aligned new).",
),
CxxLibFunction::new(
"operator new",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![
CxxLibType::SizeT,
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeInfoRef),
},
],
CxxLibEntityCategory::MemoryManagement,
"Allocates aligned array storage. (C++17 aligned new[]).",
),
CxxLibFunction::new(
"operator new",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![CxxLibType::SizeT, CxxLibType::ConstVoidPtr],
CxxLibEntityCategory::MemoryManagement,
"Placement new: constructs an object at a given address. Does not allocate.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator new[]",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![CxxLibType::SizeT, CxxLibType::ConstVoidPtr],
CxxLibEntityCategory::MemoryManagement,
"Placement new[]: constructs an array at a given address.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator new",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![
CxxLibType::SizeT,
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeInfoRef),
},
],
CxxLibEntityCategory::MemoryManagement,
"Nothrow new: returns nullptr instead of throwing on failure.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator new[]",
CxxLibHeader::New,
CxxLibType::VoidPtr,
vec![
CxxLibType::SizeT,
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeInfoRef),
},
],
CxxLibEntityCategory::MemoryManagement,
"Nothrow new[]: returns nullptr instead of throwing on failure.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator delete",
CxxLibHeader::New,
CxxLibType::Void,
vec![CxxLibType::VoidPtr],
CxxLibEntityCategory::MemoryManagement,
"Deallocates storage previously allocated by operator new.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator delete[]",
CxxLibHeader::New,
CxxLibType::Void,
vec![CxxLibType::VoidPtr],
CxxLibEntityCategory::MemoryManagement,
"Deallocates storage previously allocated by operator new[].",
)
.with_noexcept(),
CxxLibFunction::new(
"operator delete",
CxxLibHeader::New,
CxxLibType::Void,
vec![CxxLibType::VoidPtr, CxxLibType::SizeT],
CxxLibEntityCategory::MemoryManagement,
"Sized deallocation (C++14). Destructor calls delete with size of object.",
)
.with_noexcept(),
CxxLibFunction::new(
"operator delete[]",
CxxLibHeader::New,
CxxLibType::Void,
vec![CxxLibType::VoidPtr, CxxLibType::SizeT],
CxxLibEntityCategory::MemoryManagement,
"Sized array deallocation (C++14).",
)
.with_noexcept(),
CxxLibFunction::new(
"operator delete",
CxxLibHeader::New,
CxxLibType::Void,
vec![
CxxLibType::VoidPtr,
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeInfoRef),
},
],
CxxLibEntityCategory::MemoryManagement,
"Aligned deallocation (C++17).",
)
.with_noexcept(),
]
}
fn build_new_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"bad_alloc",
CxxLibHeader::New,
0,
"Exception thrown when allocation with operator new fails.",
)
.with_bases(vec!["std::exception"])
.with_methods(vec!["virtual const char* what() const noexcept"]),
CxxLibClass::new(
"nothrow_t",
CxxLibHeader::New,
0,
"Empty type used to select the non-throwing overload of operator new.",
),
]
}
fn build_new_constants() -> Vec<CxxLibConstant> {
vec![CxxLibConstant::new(
"nothrow",
CxxLibHeader::New,
"std::nothrow_t{}",
"Instance of nothrow_t used to select the non-throwing new.",
)]
}
fn build_typeinfo_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"type_info",
CxxLibHeader::TypeInfo,
0,
"Runtime type information. Returned by typeid operator.",
)
.with_methods(vec![
"virtual ~type_info()",
"bool operator==(const type_info&) const noexcept",
"bool operator!=(const type_info&) const noexcept",
"bool before(const type_info&) const noexcept",
"size_t hash_code() const noexcept",
"const char* name() const noexcept",
]),
CxxLibClass::new(
"bad_typeid",
CxxLibHeader::TypeInfo,
0,
"Exception thrown when typeid is applied to a nullptr dereference.",
)
.with_bases(vec!["std::exception"]),
CxxLibClass::new(
"bad_cast",
CxxLibHeader::TypeInfo,
0,
"Exception thrown by dynamic_cast when a reference cast fails.",
)
.with_bases(vec!["std::exception"]),
]
}
fn build_initializer_list_classes() -> Vec<CxxLibClass> {
vec![CxxLibClass::new(
"initializer_list",
CxxLibHeader::InitializerList,
1,
"Lightweight proxy object that provides access to an array of objects.",
)
.with_methods(vec![
"constexpr initializer_list() noexcept",
"constexpr size_t size() const noexcept",
"constexpr const T* begin() const noexcept",
"constexpr const T* end() const noexcept",
])]
}
fn build_initializer_list_functions() -> Vec<CxxLibFunction> {
vec![
CxxLibFunction::new(
"std::begin",
CxxLibHeader::InitializerList,
CxxLibType::Pointer {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::InitializerList {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Returns a pointer to the first element of an initializer_list.",
)
.with_constexpr()
.with_noexcept(),
CxxLibFunction::new(
"std::end",
CxxLibHeader::InitializerList,
CxxLibType::Pointer {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::InitializerList {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Returns a pointer to one past the last element of an initializer_list.",
)
.with_constexpr()
.with_noexcept(),
]
}
fn build_utility_functions() -> Vec<CxxLibFunction> {
vec![
CxxLibFunction::new(
"std::move",
CxxLibHeader::Utility,
CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Converts an lvalue to an xvalue (rvalue reference).",
)
.with_constexpr()
.with_noexcept(),
CxxLibFunction::new(
"std::forward",
CxxLibHeader::Utility,
CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Forwards an lvalue as either lvalue or rvalue, depending on T.",
)
.with_constexpr()
.with_noexcept(),
CxxLibFunction::new(
"std::swap",
CxxLibHeader::Utility,
CxxLibType::Void,
vec![
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
],
CxxLibEntityCategory::Utility,
"Swaps the values of two objects.",
)
.with_noexcept(),
CxxLibFunction::new(
"std::exchange",
CxxLibHeader::Utility,
CxxLibType::TypeParam { index: 0 },
vec![
CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::TypeParam { index: 1 }),
},
],
CxxLibEntityCategory::Utility,
"Replaces the value of obj with new_value and returns the old value.",
)
.with_constexpr()
.with_noexcept(),
CxxLibFunction::new(
"std::move_if_noexcept",
CxxLibHeader::Utility,
CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Obtains an rvalue reference if the move constructor is noexcept.",
)
.with_constexpr()
.with_noexcept(),
]
}
fn build_utility_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"pair",
CxxLibHeader::Utility,
2,
"A struct template that stores a pair of values.",
)
.with_methods(vec![
"constexpr pair()",
"constexpr pair(const T1&, const T2&)",
"template<class U1, class U2> constexpr pair(U1&&, U2&&)",
"template<class U1, class U2> constexpr pair(const pair<U1,U2>&)",
"template<class U1, class U2> constexpr pair(pair<U1,U2>&&)",
"pair& operator=(const pair&)",
"pair& operator=(pair&&)",
"void swap(pair&) noexcept",
"T1 first",
"T2 second",
]),
CxxLibClass::new(
"integer_sequence",
CxxLibHeader::Utility,
2,
"Represents a compile-time sequence of integers of type T.",
)
.with_methods(vec!["static constexpr size_t size() noexcept"]),
]
}
fn build_utility_type_aliases() -> Vec<(String, String)> {
vec![
(
"std::index_sequence".into(),
"std::integer_sequence<size_t, Is...>".into(),
),
(
"std::index_sequence_for".into(),
"std::make_index_sequence<sizeof...(T)>::type".into(),
),
(
"std::make_integer_sequence".into(),
"std::integer_sequence<T, 0, 1, 2, ..., N-1>".into(),
),
(
"std::make_index_sequence".into(),
"std::make_integer_sequence<size_t, N>".into(),
),
]
}
fn build_type_traits() -> Vec<CxxTypeTrait> {
vec![
CxxTypeTrait::new("is_void", 1, "Checks whether T is void."),
CxxTypeTrait::new("is_null_pointer", 1, "Checks whether T is std::nullptr_t."),
CxxTypeTrait::new("is_integral", 1, "Checks whether T is an integral type."),
CxxTypeTrait::new(
"is_floating_point",
1,
"Checks whether T is a floating-point type.",
),
CxxTypeTrait::new("is_array", 1, "Checks whether T is an array type."),
CxxTypeTrait::new("is_pointer", 1, "Checks whether T is a pointer type."),
CxxTypeTrait::new(
"is_lvalue_reference",
1,
"Checks whether T is an lvalue reference.",
),
CxxTypeTrait::new(
"is_rvalue_reference",
1,
"Checks whether T is an rvalue reference.",
),
CxxTypeTrait::new(
"is_member_object_pointer",
1,
"Checks whether T is a pointer to non-static member object.",
),
CxxTypeTrait::new(
"is_member_function_pointer",
1,
"Checks whether T is a pointer to non-static member function.",
),
CxxTypeTrait::new("is_enum", 1, "Checks whether T is an enumeration type."),
CxxTypeTrait::new("is_union", 1, "Checks whether T is a union type."),
CxxTypeTrait::new("is_class", 1, "Checks whether T is a non-union class type."),
CxxTypeTrait::new("is_function", 1, "Checks whether T is a function type."),
CxxTypeTrait::new(
"is_reference",
1,
"Checks whether T is an lvalue or rvalue reference.",
),
CxxTypeTrait::new(
"is_arithmetic",
1,
"Checks whether T is integral or floating-point.",
),
CxxTypeTrait::new(
"is_fundamental",
1,
"Checks whether T is arithmetic, void, or nullptr_t.",
),
CxxTypeTrait::new(
"is_object",
1,
"Checks whether T is an object type (not function, reference, or void).",
),
CxxTypeTrait::new("is_scalar", 1, "Checks whether T is scalar."),
CxxTypeTrait::new(
"is_compound",
1,
"Checks whether T is compound (not fundamental).",
),
CxxTypeTrait::new(
"is_member_pointer",
1,
"Checks whether T is pointer to non-static member.",
),
CxxTypeTrait::new("is_const", 1, "Checks whether T is const-qualified."),
CxxTypeTrait::new("is_volatile", 1, "Checks whether T is volatile-qualified."),
CxxTypeTrait::new("is_trivial", 1, "Checks whether T is trivial."),
CxxTypeTrait::new(
"is_trivially_copyable",
1,
"Checks whether T is trivially copyable.",
),
CxxTypeTrait::new(
"is_standard_layout",
1,
"Checks whether T has standard layout.",
),
CxxTypeTrait::new(
"is_pod",
1,
"Checks whether T is a POD type (deprecated in C++20).",
),
CxxTypeTrait::new(
"is_empty",
1,
"Checks whether T is a class with no non-static members.",
),
CxxTypeTrait::new(
"is_polymorphic",
1,
"Checks whether T is polymorphic (has virtual functions).",
),
CxxTypeTrait::new("is_abstract", 1, "Checks whether T is an abstract class."),
CxxTypeTrait::new("is_final", 1, "Checks whether T is a final class (C++14)."),
CxxTypeTrait::new(
"is_aggregate",
1,
"Checks whether T is an aggregate type (C++17).",
),
CxxTypeTrait::new(
"is_signed",
1,
"Checks whether T is a signed arithmetic type.",
),
CxxTypeTrait::new(
"is_unsigned",
1,
"Checks whether T is an unsigned arithmetic type.",
),
CxxTypeTrait::new(
"is_bounded_array",
1,
"Checks whether T is an array of known bound (C++20).",
),
CxxTypeTrait::new(
"is_unbounded_array",
1,
"Checks whether T is an array of unknown bound (C++20).",
),
CxxTypeTrait::new("is_same", 2, "Checks whether T and U are the same type."),
CxxTypeTrait::new(
"is_base_of",
2,
"Checks whether Base is a base class of Derived.",
),
CxxTypeTrait::new(
"is_convertible",
2,
"Checks whether From can be implicitly converted to To.",
),
CxxTypeTrait::new(
"is_constructible",
1,
"Checks whether a type can be constructed from given arguments.",
),
CxxTypeTrait::new(
"is_default_constructible",
1,
"Checks whether a type has a default constructor.",
),
CxxTypeTrait::new(
"is_copy_constructible",
1,
"Checks whether a type has a copy constructor.",
),
CxxTypeTrait::new(
"is_move_constructible",
1,
"Checks whether a type has a move constructor.",
),
CxxTypeTrait::new(
"is_assignable",
2,
"Checks whether a type can be assigned from another type.",
),
CxxTypeTrait::new(
"is_copy_assignable",
1,
"Checks whether a type has a copy assignment operator.",
),
CxxTypeTrait::new(
"is_move_assignable",
1,
"Checks whether a type has a move assignment operator.",
),
CxxTypeTrait::new(
"is_destructible",
1,
"Checks whether a type has an undeleted destructor.",
),
CxxTypeTrait::new(
"is_trivially_constructible",
1,
"Checks whether construction is trivial.",
),
CxxTypeTrait::new(
"is_trivially_default_constructible",
1,
"Checks whether default construction is trivial.",
),
CxxTypeTrait::new(
"is_trivially_copy_constructible",
1,
"Checks whether copy construction is trivial.",
),
CxxTypeTrait::new(
"is_trivially_move_constructible",
1,
"Checks whether move construction is trivial.",
),
CxxTypeTrait::new(
"is_trivially_assignable",
2,
"Checks whether assignment is trivial.",
),
CxxTypeTrait::new(
"is_trivially_copy_assignable",
1,
"Checks whether copy assignment is trivial.",
),
CxxTypeTrait::new(
"is_trivially_move_assignable",
1,
"Checks whether move assignment is trivial.",
),
CxxTypeTrait::new(
"is_trivially_destructible",
1,
"Checks whether destruction is trivial.",
),
CxxTypeTrait::new(
"is_nothrow_constructible",
1,
"Checks whether construction is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_default_constructible",
1,
"Checks whether default construction is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_copy_constructible",
1,
"Checks whether copy construction is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_move_constructible",
1,
"Checks whether move construction is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_assignable",
2,
"Checks whether assignment is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_copy_assignable",
1,
"Checks whether copy assignment is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_move_assignable",
1,
"Checks whether move assignment is noexcept.",
),
CxxTypeTrait::new(
"is_nothrow_destructible",
1,
"Checks whether destruction is noexcept.",
),
CxxTypeTrait::new(
"has_virtual_destructor",
1,
"Checks whether T has a virtual destructor.",
),
CxxTypeTrait::new(
"has_unique_object_representations",
1,
"Checks whether T has unique object representations (C++17).",
),
CxxTypeTrait::new(
"remove_cv",
1,
"Removes the topmost const and/or volatile qualifiers.",
),
CxxTypeTrait::new("remove_const", 1, "Removes the topmost const qualifier."),
CxxTypeTrait::new(
"remove_volatile",
1,
"Removes the topmost volatile qualifier.",
),
CxxTypeTrait::new("add_cv", 1, "Adds const and volatile qualifiers."),
CxxTypeTrait::new("add_const", 1, "Adds const qualifier."),
CxxTypeTrait::new("add_volatile", 1, "Adds volatile qualifier."),
CxxTypeTrait::new("remove_reference", 1, "Removes reference from a type."),
CxxTypeTrait::new(
"add_lvalue_reference",
1,
"Adds lvalue reference to a type.",
),
CxxTypeTrait::new(
"add_rvalue_reference",
1,
"Adds rvalue reference to a type.",
),
CxxTypeTrait::new("remove_pointer", 1, "Removes a pointer from a type."),
CxxTypeTrait::new("add_pointer", 1, "Adds a pointer to a type."),
CxxTypeTrait::new("make_signed", 1, "Makes an integral type signed."),
CxxTypeTrait::new("make_unsigned", 1, "Makes an integral type unsigned."),
CxxTypeTrait::new("remove_extent", 1, "Removes one array extent."),
CxxTypeTrait::new("remove_all_extents", 1, "Removes all array extents."),
CxxTypeTrait::new(
"decay",
1,
"Applies array-to-pointer, function-to-pointer, and removes cv-qualifiers.",
),
CxxTypeTrait::new(
"enable_if",
2,
"Defines a type if the condition is true, otherwise no type.",
),
CxxTypeTrait::new(
"conditional",
3,
"Selects one type or another based on a boolean condition.",
),
CxxTypeTrait::new(
"common_type",
1,
"Determines the common type among a set of types.",
),
CxxTypeTrait::new(
"underlying_type",
1,
"Determines the underlying type of an enumeration (C++11).",
),
CxxTypeTrait::new(
"result_of",
1,
"Deduces the return type of a call expression (deprecated in C++17).",
),
CxxTypeTrait::new(
"invoke_result",
1,
"Deduces the return type of INVOKE (C++17).",
),
CxxTypeTrait::new(
"void_t",
1,
"Utility metafunction that maps any types to void (C++17).",
),
CxxTypeTrait::new("conjunction", 1, "Logical AND of traits (C++17)."),
CxxTypeTrait::new("disjunction", 1, "Logical OR of traits (C++17)."),
CxxTypeTrait::new("negation", 1, "Logical NOT of a trait (C++17)."),
CxxTypeTrait::new(
"is_invocable",
1,
"Checks whether Fn can be invoked with Args... (C++17).",
),
CxxTypeTrait::new(
"is_invocable_r",
2,
"Checks whether INVOKE<Fn, Args...> returns R (C++17).",
),
CxxTypeTrait::new(
"is_nothrow_invocable",
1,
"Checks whether INVOKE is noexcept (C++17).",
),
CxxTypeTrait::new(
"is_nothrow_invocable_r",
2,
"Checks whether INVOKE is noexcept and returns R (C++17).",
),
]
}
fn build_type_traits_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"integral_constant",
CxxLibHeader::TypeTraits,
2,
"Compile-time constant of specified type with a specified value.",
)
.with_methods(vec![
"static constexpr T value = V",
"using value_type = T",
"using type = integral_constant<T, V>",
"constexpr operator value_type() const noexcept",
"constexpr value_type operator()() const noexcept",
]),
CxxLibClass::new(
"true_type",
CxxLibHeader::TypeTraits,
0,
"std::integral_constant<bool, true>.",
)
.with_bases(vec!["std::integral_constant<bool, true>"]),
CxxLibClass::new(
"false_type",
CxxLibHeader::TypeTraits,
0,
"std::integral_constant<bool, false>.",
)
.with_bases(vec!["std::integral_constant<bool, false>"]),
]
}
fn build_tuple_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"tuple",
CxxLibHeader::Tuple,
0,
"Fixed-size collection of heterogeneous values (variadic template).",
)
.with_methods(vec![
"constexpr tuple()",
"explicit constexpr tuple(const Types&...)",
"template<class... UTypes> explicit constexpr tuple(UTypes&&...)",
"tuple(const tuple&) = default",
"tuple(tuple&&) = default",
"tuple& operator=(const tuple&)",
"tuple& operator=(tuple&&)",
"template<class... UTypes> tuple& operator=(const tuple<UTypes...>&)",
"template<class... UTypes> tuple& operator=(tuple<UTypes...>&&)",
"void swap(tuple&) noexcept",
]),
CxxLibClass::new(
"tuple_size",
CxxLibHeader::Tuple,
1,
"Provides the number of elements in a tuple (at compile time).",
)
.with_methods(vec!["static constexpr size_t value"]),
CxxLibClass::new(
"tuple_element",
CxxLibHeader::Tuple,
2,
"Provides the type of the I-th element of a tuple.",
)
.with_methods(vec!["using type = /* I-th element type */"]),
]
}
fn build_tuple_functions() -> Vec<CxxLibFunction> {
let t0 = CxxLibType::TypeParam { index: 0 };
let t1 = CxxLibType::TypeParam { index: 1 };
vec![
CxxLibFunction::new(
"std::get",
CxxLibHeader::Tuple,
t0.clone(),
vec![CxxLibType::Tuple {
elements: vec![t0.clone()],
}],
CxxLibEntityCategory::TupleOps,
"Extracts the I-th element from a tuple.",
),
CxxLibFunction::new(
"std::make_tuple",
CxxLibHeader::Tuple,
CxxLibType::Tuple {
elements: vec![t0.clone(), t1.clone()],
},
vec![t0.clone(), t1.clone()],
CxxLibEntityCategory::TupleOps,
"Creates a tuple object, deducing the target type from argument types.",
),
CxxLibFunction::new(
"std::tie",
CxxLibHeader::Tuple,
CxxLibType::Tuple {
elements: vec![
CxxLibType::Reference {
elem: Box::new(t0.clone()),
},
CxxLibType::Reference {
elem: Box::new(t1.clone()),
},
],
},
vec![
CxxLibType::Reference {
elem: Box::new(t0.clone()),
},
CxxLibType::Reference {
elem: Box::new(t1.clone()),
},
],
CxxLibEntityCategory::TupleOps,
"Creates a tuple of lvalue references, useful for unpacking.",
),
CxxLibFunction::new(
"std::tuple_cat",
CxxLibHeader::Tuple,
CxxLibType::Tuple { elements: vec![] },
vec![
CxxLibType::Tuple {
elements: vec![t0.clone()],
},
CxxLibType::Tuple {
elements: vec![t1.clone()],
},
],
CxxLibEntityCategory::TupleOps,
"Concatenates any number of tuples into a single tuple.",
),
CxxLibFunction::new(
"std::forward_as_tuple",
CxxLibHeader::Tuple,
CxxLibType::Tuple {
elements: vec![t0.clone(), t1.clone()],
},
vec![t0.clone(), t1.clone()],
CxxLibEntityCategory::TupleOps,
"Constructs a tuple of references to the arguments, forwarding them.",
),
]
}
fn build_functional_classes() -> Vec<CxxLibClass> {
vec![
CxxLibClass::new(
"function",
CxxLibHeader::Functional,
1,
"General-purpose polymorphic function wrapper.",
)
.with_methods(vec![
"function() noexcept",
"function(nullptr_t) noexcept",
"function(const function&)",
"function(function&&) noexcept",
"template<class F> function(F)",
"function& operator=(const function&)",
"function& operator=(function&&)",
"function& operator=(nullptr_t) noexcept",
"template<class F> function& operator=(F&&)",
"template<class F> function& operator=(std::reference_wrapper<F>) noexcept",
"~function()",
"void swap(function&) noexcept",
"explicit operator bool() const noexcept",
"R operator()(Args...) const",
"const std::type_info& target_type() const noexcept",
"template<class T> T* target() noexcept",
"template<class T> const T* target() const noexcept",
]),
CxxLibClass::new(
"reference_wrapper",
CxxLibHeader::Functional,
1,
"Wraps a reference in a copyable, assignable object.",
)
.with_methods(vec![
"reference_wrapper(T&) noexcept",
"reference_wrapper(T&&) = delete",
"reference_wrapper(const reference_wrapper&) = default",
"reference_wrapper& operator=(const reference_wrapper&) = default",
"operator T&() const noexcept",
"T& get() const noexcept",
"template<class... Args> auto operator()(Args&&...) -> decltype(INVOKE(get(), ...))",
]),
CxxLibClass::new(
"hash",
CxxLibHeader::Functional,
1,
"Hash function object (specialized for various types).",
)
.with_methods(vec!["size_t operator()(const T&) const"]),
CxxLibClass::new(
"bad_function_call",
CxxLibHeader::Functional,
0,
"Exception thrown when calling an empty std::function.",
)
.with_bases(vec!["std::exception"]),
]
}
fn build_functional_functions() -> Vec<CxxLibFunction> {
vec![
CxxLibFunction::new(
"std::bind",
CxxLibHeader::Functional,
CxxLibType::Function {
ret: Box::new(CxxLibType::Void),
args: vec![],
},
vec![CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Void),
params: vec![],
}],
CxxLibEntityCategory::FunctionOps,
"Binds arguments to a callable object to create a new callable.",
),
CxxLibFunction::new(
"std::ref",
CxxLibHeader::Functional,
CxxLibType::ReferenceWrapper {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::FunctionOps,
"Creates a reference_wrapper, making a reference copyable.",
)
.with_noexcept(),
CxxLibFunction::new(
"std::cref",
CxxLibHeader::Functional,
CxxLibType::ReferenceWrapper {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::FunctionOps,
"Creates a reference_wrapper to a const object.",
)
.with_noexcept(),
CxxLibFunction::new(
"std::mem_fn",
CxxLibHeader::Functional,
CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Void),
params: vec![],
},
vec![CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Void),
params: vec![],
}],
CxxLibEntityCategory::FunctionOps,
"Creates a function object from a pointer to member.",
)
.with_noexcept(),
CxxLibFunction::new(
"std::not_fn",
CxxLibHeader::Functional,
CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Bool),
params: vec![],
},
vec![CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Bool),
params: vec![],
}],
CxxLibEntityCategory::FunctionOps,
"Creates a function object that returns the negation of a predicate.",
)
.with_noexcept(),
CxxLibFunction::new(
"std::invoke",
CxxLibHeader::Functional,
CxxLibType::Void,
vec![CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Void),
params: vec![],
}],
CxxLibEntityCategory::FunctionOps,
"Invokes a Callable with arguments, handling member pointers and references.",
)
.with_constexpr()
.with_noexcept(),
]
}
#[derive(Debug, Clone)]
pub struct CxxLibRegistry {
pub functions: Vec<CxxLibFunction>,
pub classes: Vec<CxxLibClass>,
pub type_traits: Vec<CxxTypeTrait>,
pub constants: Vec<CxxLibConstant>,
pub type_aliases: Vec<(String, String)>,
}
impl CxxLibRegistry {
pub fn new() -> Self {
let mut functions = Vec::new();
functions.extend(build_new_functions());
functions.extend(build_initializer_list_functions());
functions.extend(build_utility_functions());
functions.extend(build_tuple_functions());
functions.extend(build_functional_functions());
let mut classes = Vec::new();
classes.extend(build_new_classes());
classes.extend(build_typeinfo_classes());
classes.extend(build_initializer_list_classes());
classes.extend(build_utility_classes());
classes.extend(build_type_traits_classes());
classes.extend(build_tuple_classes());
classes.extend(build_functional_classes());
let type_traits = build_type_traits();
let constants = build_new_constants();
let type_aliases = build_utility_type_aliases();
CxxLibRegistry {
functions,
classes,
type_traits,
constants,
type_aliases,
}
}
pub fn functions_in_header(&self, header: CxxLibHeader) -> Vec<&CxxLibFunction> {
self.functions
.iter()
.filter(|f| f.header == header)
.collect()
}
pub fn classes_in_header(&self, header: CxxLibHeader) -> Vec<&CxxLibClass> {
self.classes.iter().filter(|c| c.header == header).collect()
}
pub fn lookup_function(&self, name: &str) -> Option<&CxxLibFunction> {
self.functions.iter().find(|f| f.name == name)
}
pub fn lookup_class(&self, name: &str) -> Option<&CxxLibClass> {
self.classes.iter().find(|c| c.name == name)
}
pub fn lookup_type_trait(&self, name: &str) -> Option<&CxxTypeTrait> {
self.type_traits.iter().find(|t| t.name == name)
}
pub fn function_count(&self) -> usize {
self.functions.len()
}
pub fn class_count(&self) -> usize {
self.classes.len()
}
pub fn type_trait_count(&self) -> usize {
self.type_traits.len()
}
}
impl Default for CxxLibRegistry {
fn default() -> Self {
Self::new()
}
}
pub fn cxx_header_for_include(filename: &str) -> Option<CxxLibHeader> {
match filename {
"<new>" | "new" => Some(CxxLibHeader::New),
"<typeinfo>" | "typeinfo" => Some(CxxLibHeader::TypeInfo),
"<initializer_list>" | "initializer_list" => Some(CxxLibHeader::InitializerList),
"<utility>" | "utility" => Some(CxxLibHeader::Utility),
"<type_traits>" | "type_traits" => Some(CxxLibHeader::TypeTraits),
"<tuple>" | "tuple" => Some(CxxLibHeader::Tuple),
"<functional>" | "functional" => Some(CxxLibHeader::Functional),
_ => None,
}
}
pub fn is_cxx_standard_header(filename: &str) -> bool {
cxx_header_for_include(filename).is_some()
}
pub fn cxx_standard_header_names() -> Vec<&'static str> {
CxxLibHeader::all().iter().map(|h| h.filename()).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cxx_header_identification() {
assert_eq!(cxx_header_for_include("<new>"), Some(CxxLibHeader::New));
assert_eq!(
cxx_header_for_include("<utility>"),
Some(CxxLibHeader::Utility)
);
assert_eq!(
cxx_header_for_include("<type_traits>"),
Some(CxxLibHeader::TypeTraits)
);
assert_eq!(cxx_header_for_include("<tuple>"), Some(CxxLibHeader::Tuple));
assert_eq!(
cxx_header_for_include("<functional>"),
Some(CxxLibHeader::Functional)
);
assert_eq!(cxx_header_for_include("<iostream>"), None);
}
#[test]
fn test_cxx_header_names() {
let names = cxx_standard_header_names();
assert!(names.contains(&"<new>"));
assert!(names.contains(&"<type_traits>"));
assert_eq!(names.len(), 7);
}
#[test]
fn test_is_cxx_standard_header() {
assert!(is_cxx_standard_header("<new>"));
assert!(is_cxx_standard_header("<tuple>"));
assert!(!is_cxx_standard_header("<vector>"));
}
#[test]
fn test_cxx_lib_header_all() {
assert_eq!(CxxLibHeader::all().len(), 7);
}
#[test]
fn test_header_filename_complete() {
for h in CxxLibHeader::all() {
assert!(h.filename().starts_with('<'));
assert!(h.filename().ends_with('>'));
}
}
#[test]
fn test_cxx_type_as_str() {
assert_eq!(CxxLibType::Void.as_str(), "void");
assert_eq!(CxxLibType::SizeT.as_str(), "size_t");
assert_eq!(
CxxLibType::Reference {
elem: Box::new(CxxLibType::Int)
}
.as_str(),
"int&"
);
assert_eq!(
CxxLibType::Pointer {
elem: Box::new(CxxLibType::Int)
}
.as_str(),
"int*"
);
}
#[test]
fn test_cxx_type_is_pointer() {
assert!(CxxLibType::VoidPtr.is_pointer());
assert!(CxxLibType::Pointer {
elem: Box::new(CxxLibType::Int)
}
.is_pointer());
assert!(!CxxLibType::Int.is_pointer());
}
#[test]
fn test_cxx_type_is_reference() {
assert!(CxxLibType::Reference {
elem: Box::new(CxxLibType::Int)
}
.is_reference());
assert!(CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::Int)
}
.is_reference());
assert!(!CxxLibType::Int.is_reference());
}
#[test]
fn test_cxx_type_display() {
let t = CxxLibType::Pair {
first: Box::new(CxxLibType::Int),
second: Box::new(CxxLibType::Pointer {
elem: Box::new(CxxLibType::Char),
}),
};
let s = format!("{}", t);
assert!(s.contains("std::pair"));
assert!(s.contains("int"));
}
#[test]
fn test_cxx_lib_function_new() {
let f = CxxLibFunction::new(
"std::move",
CxxLibHeader::Utility,
CxxLibType::RvalueRef {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
},
vec![CxxLibType::Reference {
elem: Box::new(CxxLibType::TypeParam { index: 0 }),
}],
CxxLibEntityCategory::Utility,
"Converts lvalue to rvalue.",
);
assert_eq!(f.name, "std::move");
assert_eq!(f.header, CxxLibHeader::Utility);
assert!(!f.is_noexcept);
}
#[test]
fn test_cxx_lib_function_noexcept_and_constexpr() {
let f = CxxLibFunction::new(
"std::move",
CxxLibHeader::Utility,
CxxLibType::Void,
vec![],
CxxLibEntityCategory::Utility,
"",
)
.with_noexcept()
.with_constexpr();
assert!(f.is_noexcept);
assert!(f.is_constexpr);
}
#[test]
fn test_cxx_type_trait_new() {
let t = CxxTypeTrait::new("is_same", 2, "Checks if two types are the same.");
assert_eq!(t.name, "is_same");
assert_eq!(t.template_params, 2);
assert_eq!(t.header, CxxLibHeader::TypeTraits);
}
#[test]
fn test_cxx_lib_class_new() {
let c = CxxLibClass::new("pair", CxxLibHeader::Utility, 2, "A pair of values.")
.with_bases(vec!["std::integral_constant"])
.with_methods(vec!["void swap(pair&)", "T1 first", "T2 second"]);
assert_eq!(c.name, "pair");
assert_eq!(c.template_params, 2);
assert_eq!(c.base_classes.len(), 1);
assert_eq!(c.methods.len(), 3);
}
#[test]
fn test_cxx_lib_constant_new() {
let ct = CxxLibConstant::new(
"nothrow",
CxxLibHeader::New,
"std::nothrow_t{}",
"Nothrow selector.",
);
assert_eq!(ct.name, "nothrow");
assert_eq!(ct.value, "std::nothrow_t{}");
}
#[test]
fn test_registry_creation() {
let reg = CxxLibRegistry::new();
assert!(reg.function_count() > 0);
assert!(reg.class_count() > 0);
assert!(reg.type_trait_count() > 0);
}
#[test]
fn test_registry_lookup_function() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_function("std::move").is_some());
assert!(reg.lookup_function("std::swap").is_some());
assert!(reg.lookup_function("std::forward").is_some());
}
#[test]
fn test_registry_lookup_class() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("pair").is_some());
assert!(reg.lookup_class("tuple").is_some());
assert!(reg.lookup_class("function").is_some());
}
#[test]
fn test_registry_lookup_type_trait() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_type_trait("is_same").is_some());
assert!(reg.lookup_type_trait("is_integral").is_some());
assert!(reg.lookup_type_trait("remove_reference").is_some());
assert!(reg.lookup_type_trait("enable_if").is_some());
}
#[test]
fn test_registry_functions_in_header() {
let reg = CxxLibRegistry::new();
let util_funcs = reg.functions_in_header(CxxLibHeader::Utility);
assert!(util_funcs.len() >= 4);
let names: Vec<&str> = util_funcs.iter().map(|f| f.name.as_str()).collect();
assert!(names.contains(&"std::move"));
assert!(names.contains(&"std::swap"));
}
#[test]
fn test_registry_classes_in_header() {
let reg = CxxLibRegistry::new();
let type_traits_classes = reg.classes_in_header(CxxLibHeader::TypeTraits);
assert_eq!(type_traits_classes.len(), 3);
let names: Vec<&str> = type_traits_classes
.iter()
.map(|c| c.name.as_str())
.collect();
assert!(names.contains(&"integral_constant"));
assert!(names.contains(&"true_type"));
assert!(names.contains(&"false_type"));
}
#[test]
fn test_registry_new_functions() {
let reg = CxxLibRegistry::new();
let new_funcs = reg.functions_in_header(CxxLibHeader::New);
assert!(
new_funcs.len() >= 10,
"Expected >= 10 <new> functions, got {}",
new_funcs.len()
);
}
#[test]
fn test_registry_type_trait_count() {
let reg = CxxLibRegistry::new();
let count = reg.type_trait_count();
assert!(count >= 85, "Expected >= 85 type traits, got {}", count);
}
#[test]
fn test_registry_has_bad_alloc() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("bad_alloc").is_some());
}
#[test]
fn test_registry_has_type_info() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("type_info").is_some());
}
#[test]
fn test_registry_has_initializer_list() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("initializer_list").is_some());
}
#[test]
fn test_registry_has_tuple_elements() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("tuple_size").is_some());
assert!(reg.lookup_class("tuple_element").is_some());
}
#[test]
fn test_registry_has_hash() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("hash").is_some());
}
#[test]
fn test_registry_has_reference_wrapper() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("reference_wrapper").is_some());
}
#[test]
fn test_registry_default() {
let reg = CxxLibRegistry::default();
assert!(reg.function_count() > 0);
}
#[test]
fn test_registry_type_aliases() {
let reg = CxxLibRegistry::new();
assert_eq!(reg.type_aliases.len(), 4);
}
#[test]
fn test_new_has_placement_operators() {
let reg = CxxLibRegistry::new();
let new_funcs = reg.functions_in_header(CxxLibHeader::New);
let has_placement = new_funcs.iter().any(|f| f.params.len() >= 2);
assert!(has_placement, "Should have placement new operator");
}
#[test]
fn test_utility_has_swap() {
let reg = CxxLibRegistry::new();
let f = reg.lookup_function("std::swap").unwrap();
assert!(f.is_noexcept);
}
#[test]
fn test_typeinfo_has_before_and_name() {
let reg = CxxLibRegistry::new();
let ti = reg.lookup_class("type_info").unwrap();
let methods: Vec<&str> = ti.methods.iter().map(|s| s.as_str()).collect();
assert!(methods.iter().any(|m| m.contains("before")));
assert!(methods.iter().any(|m| m.contains("name")));
}
#[test]
fn test_type_traits_has_void_t() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_type_trait("void_t").is_some());
}
#[test]
fn test_type_traits_has_invoke_result() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_type_trait("invoke_result").is_some());
}
#[test]
fn test_functional_has_bind_and_invoke() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_function("std::bind").is_some());
assert!(reg.lookup_function("std::invoke").is_some());
assert!(reg.lookup_function("std::ref").is_some());
}
#[test]
fn test_tuple_has_get_and_make() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_function("std::get").is_some());
assert!(reg.lookup_function("std::make_tuple").is_some());
assert!(reg.lookup_function("std::tie").is_some());
}
#[test]
fn test_function_class_has_operator_bool() {
let reg = CxxLibRegistry::new();
let f = reg.lookup_class("function").unwrap();
let methods: Vec<&str> = f.methods.iter().map(|s| s.as_str()).collect();
assert!(methods.iter().any(|m| m.contains("operator bool")));
}
#[test]
fn test_initializer_list_has_size_and_begin_end() {
let reg = CxxLibRegistry::new();
let il = reg.lookup_class("initializer_list").unwrap();
let methods: Vec<&str> = il.methods.iter().map(|s| s.as_str()).collect();
assert!(methods.iter().any(|m| m.contains("size")));
assert!(methods.iter().any(|m| m.contains("begin")));
assert!(methods.iter().any(|m| m.contains("end")));
}
#[test]
fn test_ctype_display_various() {
let t = CxxLibType::Tuple {
elements: vec![
CxxLibType::Int,
CxxLibType::Reference {
elem: Box::new(CxxLibType::Char),
},
CxxLibType::Pointer {
elem: Box::new(CxxLibType::Void),
},
],
};
let s = format!("{}", t);
assert!(s.contains("std::tuple"));
assert!(s.contains("int"));
}
#[test]
fn test_ctype_function_display() {
let t = CxxLibType::Function {
ret: Box::new(CxxLibType::Int),
args: vec![CxxLibType::Pointer {
elem: Box::new(CxxLibType::Char),
}],
};
let s = format!("{}", t);
assert!(s.contains("std::function"));
}
#[test]
fn test_ctype_hash_display() {
let t = CxxLibType::Hash {
elem: Box::new(CxxLibType::Int),
};
let s = format!("{}", t);
assert!(s.contains("std::hash"));
}
#[test]
fn test_ctype_integral_constant_display() {
let t = CxxLibType::IntegralConstant {
ty: Box::new(CxxLibType::Bool),
value: 1,
};
let s = format!("{}", t);
assert!(s.contains("integral_constant"));
}
#[test]
fn test_ctype_fnptr_display() {
let t = CxxLibType::FnPtr {
ret: Box::new(CxxLibType::Void),
params: vec![CxxLibType::Int],
};
let s = format!("{}", t);
assert!(s.contains("void"));
assert!(s.contains("(*)(int)"));
}
#[test]
fn test_new_bad_alloc_has_what() {
let reg = CxxLibRegistry::new();
let ba = reg.lookup_class("bad_alloc").unwrap();
let methods: Vec<&str> = ba.methods.iter().map(|s| s.as_str()).collect();
assert!(methods.iter().any(|m| m.contains("what")));
}
#[test]
fn test_typeinfo_bad_cast_exists() {
let reg = CxxLibRegistry::new();
assert!(reg.lookup_class("bad_cast").is_some());
assert!(reg.lookup_class("bad_typeid").is_some());
}
#[test]
fn test_type_trait_count_stable() {
let reg = CxxLibRegistry::new();
let count = reg.type_trait_count();
assert!(
count >= 85 && count <= 105,
"Type trait count {} outside expected range",
count
);
}
#[test]
fn test_type_traits_all_have_valid_params() {
let reg = CxxLibRegistry::new();
for t in ®.type_traits {
assert!(
t.template_params >= 1,
"Type trait '{}' should have at least 1 template param",
t.name
);
assert!(!t.name.is_empty());
assert!(!t.doc.is_empty());
}
}
#[test]
fn test_utility_pair_has_required_members() {
let reg = CxxLibRegistry::new();
let pair = reg.lookup_class("pair").unwrap();
let methods: Vec<&str> = pair.methods.iter().map(|s| s.as_str()).collect();
assert!(methods.iter().any(|m| m.contains("first")));
assert!(methods.iter().any(|m| m.contains("second")));
assert!(methods.iter().any(|m| m.contains("swap")));
}
#[test]
fn test_functional_ref_and_cref() {
let reg = CxxLibRegistry::new();
let ref_fn = reg.lookup_function("std::ref").unwrap();
let cref_fn = reg.lookup_function("std::cref").unwrap();
assert!(ref_fn.is_noexcept);
assert!(cref_fn.is_noexcept);
}
#[test]
fn test_registry_classes_count() {
let reg = CxxLibRegistry::new();
assert!(
reg.class_count() >= 15,
"Expected >= 15 classes, got {}",
reg.class_count()
);
}
#[test]
fn test_registry_functions_count() {
let reg = CxxLibRegistry::new();
assert!(
reg.function_count() >= 30,
"Expected >= 30 functions, got {}",
reg.function_count()
);
}
#[test]
fn test_cxx_header_all_iter() {
for h in CxxLibHeader::all() {
let name = h.name();
assert!(!name.is_empty());
let filename = h.filename();
assert!(!filename.is_empty());
}
}
#[test]
fn test_cxx_type_type_param() {
let t = CxxLibType::type_param(3);
assert_eq!(t.as_str(), "T3");
}
#[test]
fn test_cxx_type_with_noexcept_chain() {
let f = CxxLibFunction::new(
"std::test",
CxxLibHeader::Utility,
CxxLibType::Void,
vec![],
CxxLibEntityCategory::Utility,
"test",
)
.with_noexcept()
.with_constexpr();
assert!(f.is_noexcept);
assert!(f.is_constexpr);
}
#[test]
fn test_cxx_lib_entity_category_all() {
let categories = vec![
CxxLibEntityCategory::MemoryManagement,
CxxLibEntityCategory::TypeInfo,
CxxLibEntityCategory::Utility,
CxxLibEntityCategory::TypeTraits,
CxxLibEntityCategory::TupleOps,
CxxLibEntityCategory::FunctionOps,
];
for cat in &categories {
let _ = *cat;
}
}
#[test]
fn test_registry_constant_nothrow() {
let reg = CxxLibRegistry::new();
let ct = reg.constants.iter().find(|c| c.name == "nothrow");
assert!(ct.is_some());
assert_eq!(ct.unwrap().header, CxxLibHeader::New);
}
}