1use coco_sys::coco_suite_t;
4use std::{ffi::CString, ptr};
5
6use crate::{observer::Observer, problem::Problem};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct ProblemIdx(pub usize);
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct FunctionIdx(pub usize);
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct InstanceIdx(pub usize);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct DimensionIdx(pub usize);
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Name {
27 Bbob,
29 BbobBiobj,
31 BbobBiobjExt,
33 BbobLargescale,
35 BbobConstrained,
37 BbobMixint,
39 BbobBiobjMixint,
41 Toy,
43}
44
45impl Name {
46 fn as_str(&self) -> &'static str {
47 match self {
48 Name::Bbob => "bbob",
49 Name::BbobBiobj => "bbob-biobj",
50 Name::BbobBiobjExt => "bbob-biobj-ext",
51 Name::BbobLargescale => "bbob-largescale",
52 Name::BbobConstrained => "bbob-constrained",
53 Name::BbobMixint => "bbob-mixint",
54 Name::BbobBiobjMixint => "bbob-biobj-mixint",
55 Name::Toy => "toy",
56 }
57 }
58}
59
60pub struct Suite {
62 pub(crate) inner: *mut coco_suite_t,
63 name: CString,
64 instance: CString,
65 options: CString,
66}
67
68impl Clone for Suite {
69 fn clone(&self) -> Self {
70 Suite::new_raw(
71 self.name.clone(),
72 self.instance.clone(),
73 self.options.clone(),
74 )
75 .unwrap()
76 }
77}
78
79unsafe impl Send for Suite {}
80
81impl Suite {
82 pub fn new(name: Name, instance: &str, options: &str) -> Option<Suite> {
103 let name = CString::new(name.as_str()).unwrap();
104 let instance = CString::new(instance).unwrap();
105 let options = CString::new(options).unwrap();
106
107 Self::new_raw(name, instance, options)
108 }
109
110 fn new_raw(name: CString, instance: CString, options: CString) -> Option<Suite> {
111 let inner =
112 unsafe { coco_sys::coco_suite(name.as_ptr(), instance.as_ptr(), options.as_ptr()) };
113
114 if inner.is_null() {
115 None
116 } else {
117 Some(Suite {
118 inner,
119 name,
120 instance,
121 options,
122 })
123 }
124 }
125
126 pub fn function_from_function_index(&self, function_idx: FunctionIdx) -> usize {
128 unsafe { coco_sys::coco_suite_get_function_from_function_index(self.inner, function_idx.0) }
129 }
130
131 pub fn dimension_from_dimension_index(&self, dimension_idx: DimensionIdx) -> usize {
133 unsafe {
134 coco_sys::coco_suite_get_dimension_from_dimension_index(self.inner, dimension_idx.0)
135 }
136 }
137
138 pub fn instance_from_instance_index(&self, instance_idx: InstanceIdx) -> usize {
140 unsafe { coco_sys::coco_suite_get_instance_from_instance_index(self.inner, instance_idx.0) }
141 }
142
143 pub fn next_problem<'s>(&'s mut self, observer: Option<&mut Observer>) -> Option<Problem<'s>> {
145 let observer = observer.map(|o| o.inner).unwrap_or(ptr::null_mut());
146 let inner = unsafe { coco_sys::coco_suite_get_next_problem(self.inner, observer) };
147
148 if inner.is_null() {
149 return None;
150 }
151
152 unsafe {
153 coco_sys::coco_suite_forget_current_problem(self.inner);
154 }
155
156 Some(Problem::new(inner, self))
157 }
158
159 pub fn problem(&mut self, problem_idx: ProblemIdx) -> Option<Problem> {
161 let inner = unsafe { coco_sys::coco_suite_get_problem(self.inner, problem_idx.0) };
162
163 if inner.is_null() {
164 return None;
165 }
166
167 Some(Problem::new(inner, self))
168 }
169
170 pub fn problem_by_function_dimension_instance(
176 &mut self,
177 function: usize,
178 dimension: usize,
179 instance: usize,
180 ) -> Option<Problem> {
181 let inner = unsafe {
182 coco_sys::coco_suite_get_problem_by_function_dimension_instance(
183 self.inner,
184 function as usize,
185 dimension as usize,
186 instance as usize,
187 )
188 };
189
190 if inner.is_null() {
191 return None;
192 }
193
194 Some(Problem::new(inner, self))
195 }
196
197 pub fn number_of_problems(&self) -> usize {
199 unsafe {
200 coco_sys::coco_suite_get_number_of_problems(self.inner)
201 .try_into()
202 .unwrap()
203 }
204 }
205}
206
207impl Drop for Suite {
208 fn drop(&mut self) {
209 unsafe {
210 coco_sys::coco_suite_free(self.inner);
211 }
212 }
213}