88#![ cfg_attr( doc, feature( extended_key_value_attributes) ) ]
99#![ cfg_attr( doc, cfg_attr( doc, doc = include_str!( "../docs/c-api.md" ) ) ) ]
1010
11+ use crate :: error:: { QdkSimError , QdkSimError :: * } ;
1112use crate :: { built_info, NoiseModel , Process , State } ;
1213use lazy_static:: lazy_static;
1314use serde_json:: json;
@@ -32,12 +33,12 @@ lazy_static! {
3233
3334/// Exposes a result to C callers by setting LAST_ERROR in the Error
3435/// case, and generating an appropriate error code.
35- fn as_capi_err < F : FnOnce ( ) -> Result < ( ) , String > > ( result_fn : F ) -> i64 {
36+ fn as_capi_err < F : FnOnce ( ) -> Result < ( ) , QdkSimError > > ( result_fn : F ) -> i64 {
3637 let result = result_fn ( ) ;
3738 match result {
3839 Ok ( _) => 0 ,
39- Err ( msg ) => {
40- * LAST_ERROR . lock ( ) . unwrap ( ) = Some ( msg ) ;
40+ Err ( err ) => {
41+ * LAST_ERROR . lock ( ) . unwrap ( ) = Some ( err . to_string ( ) ) ;
4142 -1
4243 }
4344 }
@@ -47,7 +48,7 @@ fn apply<F: Fn(&NoiseModel) -> &Process>(
4748 sim_id : usize ,
4849 idxs : & [ usize ] ,
4950 channel_fn : F ,
50- ) -> Result < ( ) , String > {
51+ ) -> Result < ( ) , QdkSimError > {
5152 let state = & mut * STATE . lock ( ) . unwrap ( ) ;
5253 if let Some ( sim_state) = state. get_mut ( & sim_id) {
5354 let channel = channel_fn ( & sim_state. noise_model ) ;
@@ -59,7 +60,10 @@ fn apply<F: Fn(&NoiseModel) -> &Process>(
5960 Err ( err) => Err ( err) ,
6061 }
6162 } else {
62- return Err ( format ! ( "No simulator with id {}." , sim_id) ) ;
63+ Err ( NoSuchSimulator {
64+ invalid_id : sim_id,
65+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
66+ } )
6367 }
6468}
6569
@@ -121,11 +125,15 @@ pub unsafe extern "C" fn init(
121125) -> i64 {
122126 as_capi_err ( || {
123127 if representation. is_null ( ) {
124- return Err ( "init called with null pointer for representation". to_string ( ) ) ;
128+ return Err ( NullPointer ( " representation". to_string ( ) ) ) ;
125129 }
126- let representation = CStr :: from_ptr ( representation)
127- . to_str ( )
128- . map_err ( |e| format ! ( "UTF-8 error decoding representation argument: {}" , e) ) ?;
130+ let representation =
131+ CStr :: from_ptr ( representation)
132+ . to_str ( )
133+ . map_err ( |e| InvalidUtf8InArgument {
134+ arg_name : "representation" . to_string ( ) ,
135+ source : e,
136+ } ) ?;
129137
130138 let state = & mut * STATE . lock ( ) . unwrap ( ) ;
131139 let id = 1 + state. keys ( ) . fold ( std:: usize:: MIN , |a, b| a. max ( * b) ) ;
@@ -136,12 +144,7 @@ pub unsafe extern "C" fn init(
136144 "mixed" => State :: new_mixed ( initial_capacity) ,
137145 "pure" => State :: new_pure ( initial_capacity) ,
138146 "stabilizer" => State :: new_stabilizer ( initial_capacity) ,
139- _ => {
140- return Err ( format ! (
141- "Unknown initial state representation {}." ,
142- representation
143- ) )
144- }
147+ _ => return Err ( InvalidRepresentation ( representation. to_string ( ) ) ) ,
145148 } ,
146149 noise_model : NoiseModel :: ideal ( ) ,
147150 } ,
@@ -161,7 +164,10 @@ pub extern "C" fn destroy(sim_id: usize) -> i64 {
161164 state. remove ( & sim_id) ;
162165 Ok ( ( ) )
163166 } else {
164- Err ( format ! ( "No simulator with id {} exists." , sim_id) )
167+ Err ( NoSuchSimulator {
168+ invalid_id : sim_id,
169+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
170+ } )
165171 }
166172 } )
167173}
@@ -249,7 +255,10 @@ pub unsafe extern "C" fn m(sim_id: usize, idx: usize, result_out: *mut usize) ->
249255 * result_out = result;
250256 Ok ( ( ) )
251257 } else {
252- Err ( format ! ( "No simulator with id {} exists." , sim_id) )
258+ Err ( NoSuchSimulator {
259+ invalid_id : sim_id,
260+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
261+ } )
253262 }
254263 } )
255264}
@@ -288,7 +297,10 @@ pub extern "C" fn get_noise_model_by_name(
288297 as_capi_err ( || {
289298 let name = unsafe { CStr :: from_ptr ( name) }
290299 . to_str ( )
291- . map_err ( |e| format ! ( "UTF-8 error decoding representation argument: {}" , e) ) ?;
300+ . map_err ( |e| InvalidUtf8InArgument {
301+ arg_name : "name" . to_string ( ) ,
302+ source : e,
303+ } ) ?;
292304 let noise_model = NoiseModel :: get_by_name ( name) ?;
293305 let noise_model = CString :: new ( noise_model. as_json ( ) ) . unwrap ( ) ;
294306 unsafe {
@@ -320,20 +332,28 @@ pub extern "C" fn get_noise_model_by_name(
320332#[ no_mangle]
321333pub extern "C" fn get_noise_model ( sim_id : usize , noise_model_json : * mut * const c_char ) -> i64 {
322334 as_capi_err ( || {
323- let state = & * STATE
335+ let state = STATE
324336 . lock ( )
325- . map_err ( |e| format ! ( "Lock poisoning error: {}" , e) ) ?;
337+ . map_err ( |e| {
338+ // Note that as per https://github.com/dtolnay/anyhow/issues/81#issuecomment-609247231,
339+ // common practice is for poison errors to indicate that the containing thread
340+ // has been irrevocably corrupted and must panic.
341+ panic ! ( "The lock on shared state for the C API has been poisoned." ) ;
342+ } )
343+ . unwrap ( ) ;
326344 if let Some ( sim_state) = state. get ( & sim_id) {
327- let c_str = CString :: new ( sim_state. noise_model . as_json ( ) . as_str ( ) ) . map_err ( |e| {
328- format ! ( "Null error while converting noise model to C string: {}" , e)
329- } ) ?;
345+ let c_str = CString :: new ( sim_state. noise_model . as_json ( ) . as_str ( ) )
346+ . map_err ( |e| UnanticipatedCApiError ( anyhow:: Error :: new ( e) ) ) ?;
330347 unsafe {
331348 * noise_model_json = c_str. into_raw ( ) ;
332- }
349+ } ;
350+ Ok ( ( ) )
333351 } else {
334- return Err ( format ! ( "No simulator with id {} exists." , sim_id) ) ;
352+ Err ( NoSuchSimulator {
353+ invalid_id : sim_id,
354+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
355+ } )
335356 }
336- Ok ( ( ) )
337357 } )
338358}
339359
@@ -354,7 +374,7 @@ pub extern "C" fn get_noise_model(sim_id: usize, noise_model_json: *mut *const c
354374pub unsafe extern "C" fn set_noise_model ( sim_id : usize , new_model : * const c_char ) -> i64 {
355375 as_capi_err ( || {
356376 if new_model. is_null ( ) {
357- return Err ( "set_noise_model called with null pointer ". to_string ( ) ) ;
377+ return Err ( NullPointer ( "new_model ". to_string ( ) ) ) ;
358378 }
359379
360380 let c_str = CStr :: from_ptr ( new_model) ;
@@ -366,25 +386,18 @@ pub unsafe extern "C" fn set_noise_model(sim_id: usize, new_model: *const c_char
366386 sim_state. noise_model = noise_model;
367387 Ok ( ( ) )
368388 } else {
369- Err ( format ! ( "No simulator with id {} exists." , sim_id) )
389+ Err ( NoSuchSimulator {
390+ invalid_id : sim_id,
391+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
392+ } )
370393 }
371394 }
372- Err ( serialization_error) => Err ( format ! (
373- "{} error deserializing noise model at line {}, column {}." ,
374- match serialization_error. classify( ) {
375- serde_json:: error:: Category :: Data => "Data / schema" ,
376- serde_json:: error:: Category :: Eof => "End-of-file" ,
377- serde_json:: error:: Category :: Io => "I/O" ,
378- serde_json:: error:: Category :: Syntax => "Syntax" ,
379- } ,
380- serialization_error. line( ) ,
381- serialization_error. column( )
382- ) ) ,
395+ Err ( err) => Err ( JsonDeserializationError ( err) ) ,
383396 } ,
384- Err ( msg) => Err ( format ! (
385- "UTF-8 error decoding serialized noise model; was valid until byte {}." ,
386- msg. valid_up_to ( )
387- ) ) ,
397+ Err ( msg) => Err ( InvalidUtf8InArgument {
398+ arg_name : "new_model" . to_string ( ) ,
399+ source : msg,
400+ } ) ,
388401 }
389402 } )
390403}
@@ -406,19 +419,25 @@ pub unsafe extern "C" fn set_noise_model(sim_id: usize, new_model: *const c_char
406419pub unsafe extern "C" fn set_noise_model_by_name ( sim_id : usize , name : * const c_char ) -> i64 {
407420 as_capi_err ( || {
408421 if name. is_null ( ) {
409- return Err ( "set_noise_model_by_name called with null pointer ". to_string ( ) ) ;
422+ return Err ( NullPointer ( "name ". to_string ( ) ) ) ;
410423 }
411424
412425 let name = CStr :: from_ptr ( name)
413426 . to_str ( )
414- . map_err ( |e| format ! ( "UTF-8 error decoding name: {}" , e) ) ?;
427+ . map_err ( |e| InvalidUtf8InArgument {
428+ arg_name : "name" . to_string ( ) ,
429+ source : e,
430+ } ) ?;
415431 let noise_model = NoiseModel :: get_by_name ( name) ?;
416432 let state = & mut * STATE . lock ( ) . unwrap ( ) ;
417433 if let Some ( sim_state) = state. get_mut ( & sim_id) {
418434 sim_state. noise_model = noise_model;
419435 Ok ( ( ) )
420436 } else {
421- Err ( format ! ( "No simulator with id {} exists." , sim_id) )
437+ Err ( NoSuchSimulator {
438+ invalid_id : sim_id,
439+ expected : state. keys ( ) . into_iter ( ) . cloned ( ) . collect ( ) ,
440+ } )
422441 }
423442 } )
424443}
0 commit comments