cqc/hdr/mod.rs
1//! # CQC Interface
2//!
3//! This module documents the [CQC Interface
4//! specification](https://softwarequtech.github.io/CQC-Python/interface.html)
5//! and defines the necessary constants and header structures.
6//!
7//! # CQC Header
8//!
9//! Every CQC message begins with a CQC header.
10//!
11//! ```text
12//! Field Length Meaning
13//! ----- ------ -------
14//! version 1 byte CQC interface version. Current version is 2.
15//! type 1 byte Message type.
16//! app_id 2 bytes Application ID. Return messages will be tagged
17//! appropriately.
18//! length 4 bytes Total length of the CQC instruction packet.
19//! ```
20//!
21//! A CQC Command Header MUST follow the CQC Header for the following messages:
22//!
23//! - Command
24//! - Factory
25//! - GetTime
26//!
27//! ## CQC Header Message Types
28//!
29//! The supported message types. They are split into normal types (Tp) and
30//! error types (Err).
31//!
32//! ```text
33//! Type Name Meaning
34//! ---- ---- -------
35//! 0 Hello Alive check.
36//! 1 Command Execute a command list.
37//! 2 Factory Start executing command list repeatedly.
38//! 3 Expire Qubit has expired.
39//! 4 Done Command execution done.
40//! 5 Recv Received qubit.
41//! 6 EprOk Created EPR pair.
42//! 7 MeasOut Measurement outcome.
43//! 8 GetTime Get creation time of qubit.
44//! 9 InfTime Get timing informaiton.
45//! 10 NewOk Created new qubit.
46//! 11 Mix Multiple header types will follow.
47//! 12 If Perform a conditional action.
48//!
49//! 20 General General purpose error (no details).
50//! 21 NoQubit No more qubits available.
51//! 22 Unsupp Command sequence not supported.
52//! 23 Timeout Timeout.
53//! 24 InUse Qubit already in use.
54//! 25 Unknown Unknown qubit ID.
55//! ```
56//!
57//! # CQC Command Header
58//!
59//! A CQC Command Header identifies the specific instruction to execute, as
60//! well as the qubit ID on which to perform this instructions.
61//!
62//! A CQC Command Header MUST follow the CQC Header for the following messages:
63//!
64//! - Command
65//! - Factory
66//! - GetTime
67//!
68//! ```text
69//! Field Length Meaning
70//! ----- ------ -------
71//! qubit_id 2 bytes Qubit ID to perform the operation on.
72//! instr 1 byte Instruction to perform.
73//! options 1 byte Options when executing the command.
74//! ```
75//!
76//! ## Notify
77//!
78//! If the notify option bit is set, each of these commands return a CQC
79//! message Done indicating that execution has completed. Some commands also
80//! return additional messages, as described below:
81//!
82//! - New: Returns a NewOk reply followed by an Extra Qubit header with the
83//! qubit ID.
84//! - Measure(InPlace): Returns a MeasOut message followed by a Measurement
85//! Outcome header containing the measurement outcome.
86//! - Recv: Returns a Recv reply followed by an Extra Qubit header with the
87//! qubit ID.
88//! - Epr(Recv): Returns an EprOk reply by an Extra Qubit header and an
89//! Entanglement Information header.
90//!
91//! ## CQC Command Header Instruction Types
92//!
93//! The supported CQC instructions.
94//!
95//! ```text
96//! Type Name Meaning
97//! ---- ---- -------
98//! 0 I Identity (do nothing, wait one step).
99//! 1 New Ask for a new qubit.
100//! 2 Measure Measure qubit.
101//! 3 MeasureInPlace Measure qubit in-place.
102//! 4 Reset Reset qubit to |0>.
103//! 5 Send Send qubit to another node.
104//! 6 Recv Ask to receive qubit.
105//! 7 Epr Create EPR pair with the specified node.
106//! 8 EprRecv Receive EPR pair.
107//!
108//! 10 X Pauli X.
109//! 11 Z Pauli Z.
110//! 12 Y Pauli Y.
111//! 13 T T Gate.
112//! 14 RotX Rotation over angle around X in pi/256 increments.
113//! 15 RotY Rotation over angle around Y in pi/256 increments.
114//! 16 RotZ Rotation over angle around Z in pi/256 increments.
115//! 17 H Hadamard Gate.
116//! 18 K K Gate - taking computational to Y eigenbasis.
117//!
118//! 20 Cnot CNOT Gate with this as control.
119//! 21 Cphase CPHASE Gate with this as control.
120//!
121//! 22 Allocate Allocate a number of qubits.
122//! 23 Release Release a qubit.
123//! ```
124//!
125//! ## CQC Command Header options
126//!
127//! Command options are set as bit flags.
128//!
129//! ```text
130//! Flag Name Meaning
131//! ---- ---- -------
132//! 0x01 Notify Send a notification when command completes.
133//! 0x02 Action On if there are actions to execute when done.
134//! 0x04 Block Block until command is done.
135//! 0x08 IfThen Execute command after done.
136//! ```
137//!
138//! # CQC Assign Header
139//!
140//! Additional header used to store a measurement outcome in the backend and
141//! assign it a reference ID. Every measurement command (CQC_CMD_MEASURE or
142//! CQC_CMD_MEASURE_INPLACE) is followed by a CQC Assign Header. The value can
143//! be retrieved by future instructions by refering to this ID.
144//!
145//! ```text
146//! Field Length Meaning
147//! ----- ------ -------
148//! ref_id 4 bytes Reference ID for the measurement` value.
149//! ``
150//!
151//! # CQC Rotation Header
152//!
153//! Additional header used to define the rotation angle of a rotation gate.
154//!
155//! ```text
156//! Field Length Meaning
157//! ----- ------ -------
158//! step 1 byte Angle step of rotation (increments of 1/256).
159//! ```
160//!
161//! # CQC Extra Qubit Header
162//!
163//! Additional header used to send the qubit_id of a secondary qubit for two
164//! qubit gates.
165//!
166//! ```text
167//! Field Length Meaning
168//! ----- ------ -------
169//! qubit_id 2 bytes ID of the target qubit.
170//! ```
171//!
172//! # CQC Communication Header
173//!
174//! Additional header used to send to which node to send information to. Used
175//! in send and EPR commands.
176//!
177//! ```text
178//! Field Length Meaning
179//! ----- ------ -------
180//! remote_app_id 2 bytes Remote application ID.
181//! remote_port 2 bytes Port of the remote node for sending classical
182//! control info.
183//! remote_node 4 bytes IP of the remote node (IPv4).
184//! ```
185//!
186//! # CQC Factory Header
187//!
188//! Additional header used to send factory information. Factory commands are
189//! used to tell the backend to do the following command or a sequence of
190//! commands multiple times.
191//!
192//! ```text
193//! Field Length Meaning
194//! ----- ------ -------
195//! num_iter 1 byte Number of iterations to do the sequence.
196//! options 1 byte Options when executing the factory.
197//! ```
198//!
199//! ## CQC Factory Header options
200//!
201//! Factory options are set as bit flags.
202//!
203//! ```text
204//! Flag Name Meaning
205//! ---- ---- -------
206//! 0x01 Notify Send a notification when command completes.
207//! 0x04 Block Block until factory is done.
208//! ```
209//!
210//! # CQC Measurement Outcome Header
211//!
212//! Additional header used to send the outcome of a measurement.
213//!
214//! ```text
215//! Field Length Meaning
216//! ----- ------ -------
217//! meas_out 1 byte Measurement outcome.
218//! ```
219//!
220//! # CQC Time Info Header
221//!
222//! Additional header used to send time information in response to the GetTime
223//! command.
224//!
225//! ```text
226//! Field Length Meaning
227//! ----- ------ -------
228//! datetime 8 bytes Time of creation.
229//! ```
230//!
231//! # CQC Entanglement Information Header
232//!
233//! When an EPR-pair is created the CQC Backend will return information about
234//! the entanglement which can be used in a entanglement management protocol.
235//! The entanglement information header contains information about the parties
236//! that share the EPR-pair, the time of creation, how good the entanglement is
237//! (goodness). Furthermore, the entanglement information header contain a
238//! entanglement ID (id_AB) which can be used to keep track of the entanglement
239//! in the network. The entanglement ID is incremented with respect to the
240//! pair of nodes and who initialized the entanglement (DF). For this reason
241//! the entanglement ID together with the nodes and the directionality flag
242//! gives a unique way to identify the entanglement in the network.
243//!
244//! ```text
245//! Field Length Meaning
246//! ----- ------ -------
247//! node_A 4 bytes IP of this node.
248//! port_A 2 bytes Port of this node.
249//! app_id_A 2 bytes App ID of this node.
250//! node_B 4 bytes IP of other node.
251//! port_B 2 bytes Port of other node.
252//! app_id_B 2 bytes App ID of other node.
253//! id_AB 4 bytes Entanglement ID.
254//! timestamp 8 bytes Time of creation.
255//! ToG 8 bytes Time of goodness.
256//! goodness 2 bytes Goodness (estimate of the fidelity of state).
257//! DF 1 byte Directionality flag (0=Mid, 1=node_A, 2=node_B).
258//! align 1 byte 4 byte alignment.
259//! ```
260//!
261//! # CQC Type Header
262//!
263//! A top-level CQC header of type Mix may be followed by multiple other header
264//! types. Each new header is announced by the CQC type header.
265//!
266//! ```text
267//! Field Length Meaning
268//! ----- ------ -------
269//! type 1 byte Type of next header (except Mix).
270//! length 4 bytes Number of bytes until the next type header.
271//! ```
272//!
273//! # CQC If Header
274//!
275//! The If header can only be used inside programs of type Mix. Execute the
276//! following command only if the specified condition is true.
277//!
278//! ```text
279//! Field Length Meaning
280//! ----- ------ -------
281//! left_operand 4 bytes Refernce ID of the first operand.
282//! operator 1 byte Comparison operator.
283//! right_type 1 byte Type of second operand.
284//! right_operand 4 bytes Reference ID or value of second operand.
285//! length 4 bytes Length in bytes of following command.
286//! ```
287//!
288//! ## CQC If Header Operator Types
289//!
290//! ```text
291//! Type Name Meaning
292//! ---- ---- -------
293//! 0 Eq Compare for equality.
294//! 1 InEq Compare for inequality.
295//! ```
296//!
297//! ## CQC If Header Right Operand Types
298//!
299//! ```text
300//! Type Name Meaning
301//! ---- ---- -------
302//! 0 Value Right operand holds raw value.
303//! 1 RefId Right operand holds reference ID.
304//! ```
305
306extern crate serde;
307
308use self::serde::de;
309use std::fmt;
310use std::fmt::Display;
311
312use self::serde::de::Visitor;
313use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
314
315#[macro_use]
316mod macros;
317
318/// # CQC Version
319///
320/// The current supported versions are: 2.
321/// The currently unsupported versions are: 0, 1.
322#[repr(u8)]
323#[derive(Copy, Clone, Debug, PartialEq)]
324pub enum Version {
325 V2 = 2,
326}
327
328impl Version {
329 /// Convert an 8-bit value to a version value. Returns `None` if the value
330 /// does not correspond to a currently supported version.
331 #[inline]
332 pub fn get(value: u8) -> Option<Version> {
333 let version = match value {
334 2 => Version::V2,
335 _ => return None,
336 };
337
338 Some(version)
339 }
340}
341
342serde_enum_u8!(Version, VersionVisitor, "CQC version");
343
344/// # CQC Header
345///
346/// Every CQC message begins with a CQC header.
347///
348/// ```text
349/// Field Length Meaning
350/// ----- ------ -------
351/// version 1 byte CQC interface version. Current version is 2.
352/// type 1 byte Message type.
353/// app_id 2 bytes Application ID. Return messages will be tagged
354/// appropriately.
355/// length 4 bytes Total length of the CQC instruction packet.
356/// ```
357///
358/// A CQC Command Header MUST follow the CQC Header for the following messages:
359///
360/// - Command
361/// - Factory
362/// - GetTime
363#[derive(Serialize, Deserialize, Debug, PartialEq)]
364pub struct CqcHdr {
365 pub version: Version,
366 pub msg_type: MsgType,
367 pub app_id: u16,
368 pub length: u32,
369}
370
371def_len!(CqcHdr, 8);
372
373/// # CQC Header Message Types
374///
375/// The supported message types. They are split into normal types (Tp) and
376/// error types (Err).
377///
378/// ```text
379/// Type Name Meaning
380/// ---- ---- -------
381/// 0 Hello Alive check.
382/// 1 Command Execute a command list.
383/// 2 Factory Start executing command list repeatedly.
384/// 3 Expire Qubit has expired.
385/// 4 Done Command execution done.
386/// 5 Recv Received qubit.
387/// 6 EprOk Created EPR pair.
388/// 7 MeasOut Measurement outcome.
389/// 8 GetTime Get creation time of qubit.
390/// 9 InfTime Get timing informaiton.
391/// 10 NewOk Created new qubit.
392/// 11 Mix Multiple header types will follow.
393/// 12 If Perform a conditional action.
394///
395/// 20 General General purpose error (no details).
396/// 21 NoQubit No more qubits available.
397/// 22 Unsupp Command sequence not supported.
398/// 23 Timeout Timeout.
399/// 24 InUse Qubit already in use.
400/// 25 Unknown Unknown qubit ID.
401/// ```
402#[derive(Copy, Clone, Debug, Display, PartialEq)]
403pub enum MsgType {
404 Tp(Tp),
405 Err(Err),
406}
407
408impl From<MsgType> for u8 {
409 fn from(msg_type: MsgType) -> Self {
410 match msg_type {
411 MsgType::Tp(val) => val as u8,
412 MsgType::Err(val) => val as u8,
413 }
414 }
415}
416
417macro_rules! def_is_tp {
418 ($tp: pat, $name: ident) => {
419 #[inline]
420 pub fn $name(&self) -> bool {
421 match self {
422 &MsgType::Tp($tp) => true,
423 _ => false,
424 }
425 }
426 }
427}
428
429macro_rules! def_is_err {
430 ($tp: pat, $name: ident) => {
431 #[inline]
432 pub fn $name(&self) -> bool {
433 match self {
434 &MsgType::Err($tp) => true,
435 _ => false,
436 }
437 }
438 }
439}
440
441impl MsgType {
442 #[inline]
443 pub fn is_tp(&self) -> bool {
444 match self {
445 &MsgType::Tp(_) => true,
446 &MsgType::Err(_) => false,
447 }
448 }
449
450 #[inline]
451 pub fn is_err(&self) -> bool {
452 match self {
453 &MsgType::Tp(_) => false,
454 &MsgType::Err(_) => true,
455 }
456 }
457
458 def_is_tp!(Tp::Hello, is_hello);
459 def_is_tp!(Tp::Command, is_command);
460 def_is_tp!(Tp::Factory, is_factory);
461 def_is_tp!(Tp::Expire, is_expire);
462 def_is_tp!(Tp::Done, is_done);
463 def_is_tp!(Tp::Recv, is_recv);
464 def_is_tp!(Tp::EprOk, is_epr_ok);
465 def_is_tp!(Tp::MeasOut, is_measout);
466 def_is_tp!(Tp::GetTime, is_get_time);
467 def_is_tp!(Tp::InfTime, is_inf_time);
468 def_is_tp!(Tp::NewOk, is_new_ok);
469 def_is_tp!(Tp::Mix, is_mix);
470 def_is_tp!(Tp::If, is_if);
471
472 def_is_err!(Err::General, is_err_general);
473 def_is_err!(Err::NoQubit, is_err_noqubit);
474 def_is_err!(Err::Unsupp, is_err_unsupp);
475 def_is_err!(Err::Timeout, is_err_timeout);
476 def_is_err!(Err::InUse, is_err_inuse);
477 def_is_err!(Err::Unknown, is_err_unknown);
478
479 /// Convert an 8-bit value to a message type. Returns `None` if the value
480 /// does not correspond to a valid message type.
481 #[inline]
482 pub fn get(value: u8) -> Option<MsgType> {
483 let msg_type = if value <= Tp::If as u8 {
484 MsgType::Tp(Tp::get(value).unwrap())
485 } else if value >= Err::General as u8 && value <= Err::Unknown as u8 {
486 MsgType::Err(Err::get(value).unwrap())
487 } else {
488 return None;
489 };
490
491 Some(msg_type)
492 }
493}
494
495impl Serialize for MsgType {
496 #[inline]
497 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
498 where
499 S: Serializer,
500 {
501 match self {
502 &MsgType::Tp(tp) => serializer.serialize_u8(tp as u8),
503 &MsgType::Err(err) => serializer.serialize_u8(err as u8),
504 }
505 }
506}
507
508deserialize_enum_u8!(MsgType, MsgTypeVisitor, "CQC message type");
509
510/// # CQC Header Normal Message Types
511///
512/// The supported normal message types.
513///
514/// ```text
515/// Type Name Meaning
516/// ---- ---- -------
517/// 0 Hello Alive check.
518/// 1 Command Execute a command list.
519/// 2 Factory Start executing command list repeatedly.
520/// 3 Expire Qubit has expired.
521/// 4 Done Command execution done.
522/// 5 Recv Received qubit.
523/// 6 EprOk Created EPR pair.
524/// 7 MeasOut Measurement outcome.
525/// 8 GetTime Get creation time of qubit.
526/// 9 InfTime Get timing informaiton.
527/// 10 NewOk Created new qubit.
528/// 11 Mix Multiple header types will follow.
529/// 12 If Perform a conditional action.
530/// ```
531#[repr(u8)]
532#[derive(Copy, Clone, Debug, Display, PartialEq)]
533pub enum Tp {
534 Hello = 0, // Alive check.
535 Command = 1, // Execute a command list.
536 Factory = 2, // Start executing command list repeatedly.
537 Expire = 3, // Qubit has expired.
538 Done = 4, // Command execution done.
539 Recv = 5, // Recevied qubit.
540 EprOk = 6, // Created EPR pair.
541 MeasOut = 7, // Measurement outcome.
542 GetTime = 8, // Get creation time of qubit.
543 InfTime = 9, // Inform about time.
544 NewOk = 10, // Created new qubit.
545 Mix = 11, // Multiple header types will follow.
546 If = 12, // Perform a conditional action.
547}
548
549impl Tp {
550 /// Convert an 8-bit value to a normal message type. Returns `None` if the
551 /// value does not correspond to a valid normal message type.
552 #[inline]
553 pub fn get(value: u8) -> Option<Tp> {
554 let msg_type = match value {
555 0 => Tp::Hello,
556 1 => Tp::Command,
557 2 => Tp::Factory,
558 3 => Tp::Expire,
559 4 => Tp::Done,
560 5 => Tp::Recv,
561 6 => Tp::EprOk,
562 7 => Tp::MeasOut,
563 8 => Tp::GetTime,
564 9 => Tp::InfTime,
565 10 => Tp::NewOk,
566 11 => Tp::Mix,
567 12 => Tp::If,
568
569 _ => return None,
570 };
571
572 Some(msg_type)
573 }
574}
575
576serde_enum_u8!(Tp, TpVisitor, "CQC normal message type");
577
578/// # CQC Header Error Message Types
579///
580/// The supported error message types.
581///
582/// ```text
583/// Type Name Meaning
584/// ---- ---- -------
585/// 20 General General purpose error (no details).
586/// 21 NoQubit No more qubits available.
587/// 22 Unsupp Command sequence not supported.
588/// 23 Timeout Timeout.
589/// 24 InUse Qubit already in use.
590/// 25 Unknown Unknown qubit ID.
591/// ```
592#[repr(u8)]
593#[derive(Copy, Clone, Debug, Display, PartialEq)]
594pub enum Err {
595 General = 20, // General purpose error (no details).
596 NoQubit = 21, // No more qubits available.
597 Unsupp = 22, // Command sequence not supported.
598 Timeout = 23, // Timeout.
599 InUse = 24, // Qubit already in use.
600 Unknown = 25, // Unknown qubit ID
601}
602
603impl Err {
604 /// Convert an 8-bit value to an error message type. Returns `None` if the
605 /// value does not correspond to a valid normal message type.
606 #[inline]
607 pub fn get(value: u8) -> Option<Err> {
608 let msg_type = match value {
609 20 => Err::General,
610 21 => Err::NoQubit,
611 22 => Err::Unsupp,
612 23 => Err::Timeout,
613 24 => Err::InUse,
614 25 => Err::Unknown,
615
616 _ => return None,
617 };
618
619 Some(msg_type)
620 }
621}
622
623serde_enum_u8!(Err, ErrVisitor, "CQC error message type");
624
625/// # CQC Command Header
626///
627/// A CQC Command Header identifies the specific instruction to execute, as
628/// well as the qubit ID on which to perform this instructions.
629///
630/// A CQC Command Header MUST follow the CQC Header for the following messages:
631///
632/// - Command
633/// - Factory
634/// - GetTime
635///
636/// ```text
637/// Field Length Meaning
638/// ----- ------ -------
639/// qubit_id 2 bytes Qubit ID to perform the operation on.
640/// instr 1 byte Instruction to perform.
641/// options 1 byte Options when executing the command.
642/// ```
643///
644/// ## Notify
645///
646/// If the notify option bit is set, each of these commands return a CQC
647/// message Done indicating that execution has completed. Some commands also
648/// return additional messages, as described below:
649///
650/// - New: Returns a NewOk reply followed by an Extra Qubit header with the
651/// qubit ID.
652/// - Measure(InPlace): Returns a MeasOut message followed by a Measurement
653/// Outcome header containing the measurement outcome.
654/// - Recv: Returns a Recv reply followed by an Extra Qubit header with the
655/// qubit ID.
656/// - Epr(Recv): Returns an EprOk reply by an Extra Qubit header and an
657/// Entanglement Information header.
658#[derive(Serialize, Deserialize, Debug, PartialEq)]
659pub struct CmdHdr {
660 pub qubit_id: u16,
661 pub instr: Cmd,
662 pub options: CmdOpt,
663}
664
665def_len!(CmdHdr, 4);
666
667/// # CQC Command Header Instruction Types
668///
669/// The supported CQC instructions.
670///
671/// ```text
672/// Type Name Meaning
673/// ---- ---- -------
674/// 0 I Identity (do nothing, wait one step).
675/// 1 New Ask for a new qubit.
676/// 2 Measure Measure qubit.
677/// 3 MeasureInPlace Measure qubit in-place.
678/// 4 Reset Reset qubit to |0>.
679/// 5 Send Send qubit to another node.
680/// 6 Recv Ask to receive qubit.
681/// 7 Epr Create EPR pair with the specified node.
682/// 8 EprRecv Receive EPR pair.
683///
684/// 10 X Pauli X.
685/// 11 Z Pauli Z.
686/// 12 Y Pauli Y.
687/// 13 T T Gate.
688/// 14 RotX Rotation over angle around X in pi/256 increments.
689/// 15 RotY Rotation over angle around Y in pi/256 increments.
690/// 16 RotZ Rotation over angle around Z in pi/256 increments.
691/// 17 H Hadamard Gate.
692/// 18 K K Gate - taking computational to Y eigenbasis.
693///
694/// 20 Cnot CNOT Gate with this as control.
695/// 21 Cphase CPHASE Gate with this as control.
696///
697/// 22 Allocate Allocate a number of qubits.
698/// 23 Release Release a qubit.
699/// ```
700#[repr(u8)]
701#[derive(Copy, Clone, Debug, PartialEq)]
702pub enum Cmd {
703 I = 0, // Identity (do nothing, wait one step).
704 New = 1, // Ask for a new qubit.
705 Measure = 2, // Measure qubit.
706 MeasureInplace = 3, // Measure qubit in-place.
707 Reset = 4, // Reset qubit to |0>.
708 Send = 5, // Send qubit to another node.
709 Recv = 6, // Ask to receive qubit.
710 Epr = 7, // Create EPR pair with the specified node.
711 EprRecv = 8, // Receive EPR pair.
712
713 X = 10, // Pauli X.
714 Z = 11, // Pauli Z.
715 Y = 12, // Pauli Y.
716 T = 13, // T Gate.
717 RotX = 14, // Rotation over angle around X in pi/256 increments.
718 RotY = 15, // Rotation over angle around Y in pi/256 increments.
719 RotZ = 16, // Rotation over angle around Z in pi/256 increments.
720 H = 17, // Hadamard Gate.
721 K = 18, // K Gate - taking computational to Y eigenbasis.
722
723 Cnot = 20, // CNOT Gate with this as control.
724 Cphase = 21, // CPHASE Gate with this as control.
725
726 Allocate = 22, // Allocate a number of qubits.
727 Release = 23, // Release a qubit.
728}
729
730impl Cmd {
731 /// Convert an 8-bit value to a command type. Returns `None` if the value
732 /// does not correspond to a valid command type.
733 #[inline]
734 pub fn get(value: u8) -> Option<Cmd> {
735 let command = match value {
736 0 => Cmd::I,
737 1 => Cmd::New,
738 2 => Cmd::Measure,
739 3 => Cmd::MeasureInplace,
740 4 => Cmd::Reset,
741 5 => Cmd::Send,
742 6 => Cmd::Recv,
743 7 => Cmd::Epr,
744 8 => Cmd::EprRecv,
745
746 10 => Cmd::X,
747 11 => Cmd::Z,
748 12 => Cmd::Y,
749 13 => Cmd::T,
750 14 => Cmd::RotX,
751 15 => Cmd::RotY,
752 16 => Cmd::RotZ,
753 17 => Cmd::H,
754 18 => Cmd::K,
755
756 20 => Cmd::Cnot,
757 21 => Cmd::Cphase,
758
759 22 => Cmd::Allocate,
760 23 => Cmd::Release,
761
762 _ => return None,
763 };
764
765 Some(command)
766 }
767}
768
769serde_enum_u8!(Cmd, CmdVisitor, "CQC instruction type");
770
771bitflags! {
772 /// # CQC Command Header options
773 ///
774 /// Command options are set as bit flags.
775 ///
776 /// ```text
777 /// Flag Name Meaning
778 /// ---- ---- -------
779 /// 0x01 Notify Send a notification when command completes.
780 /// 0x02 Action On if there are actions to execute when done.
781 /// 0x04 Block Block until command is done.
782 /// 0x08 IfThen Execute command after done.
783 /// ```
784 pub struct CmdOpt: u8 {
785 const NOTIFY = 0x01;
786 const ACTION = 0x02;
787 const BLOCK = 0x04;
788 const IFTHEN = 0x08;
789 }
790}
791
792impl CmdOpt {
793 def_set_flag!(CmdOpt, NOTIFY, set_notify);
794 def_set_flag!(CmdOpt, ACTION, set_action);
795 def_set_flag!(CmdOpt, BLOCK, set_block);
796 def_set_flag!(CmdOpt, IFTHEN, set_ifthen);
797
798 def_get_flag!(CmdOpt, NOTIFY, get_notify);
799 def_get_flag!(CmdOpt, ACTION, get_action);
800 def_get_flag!(CmdOpt, BLOCK, get_block);
801 def_get_flag!(CmdOpt, IFTHEN, get_ifthen);
802}
803
804serde_option_u8!(CmdOpt, CmdOptVisitor, "command");
805
806/// # CQC Assign Header
807///
808/// Additional header used to store a measurement outcome in the backend and
809/// assign it a reference ID. Every measurement command (CQC_CMD_MEASURE or
810/// CQC_CMD_MEASURE_INPLACE) is followed by a CQC Assign Header. The value can
811/// be retrieved by future instructions by refering to this ID.
812///
813/// ```text
814/// Field Length Meaning
815/// ----- ------ -------
816/// ref_id 4 bytes Reference ID for the measurement` value.
817/// ```
818#[derive(Serialize, Deserialize, Debug, PartialEq)]
819pub struct AssignHdr {
820 pub ref_id: u32,
821}
822
823def_len!(AssignHdr, 4);
824
825/// # CQC Rotation Header
826///
827/// Additional header used to define the rotation angle of a rotation gate.
828///
829/// ```text
830/// Field Length Meaning
831/// ----- ------ -------
832/// step 1 byte Angle step of rotation (increments of 1/256).
833/// ```
834#[derive(Serialize, Deserialize, Debug, PartialEq)]
835pub struct RotHdr {
836 pub step: u8,
837}
838
839def_len!(RotHdr, 1);
840
841/// # CQC Extra Qubit Header
842///
843/// Additional header used to send the qubit_id of a secondary qubit for two
844/// qubit gates.
845///
846/// ```text
847/// Field Length Meaning
848/// ----- ------ -------
849/// qubit_id 2 bytes ID of the target qubit.
850/// ```
851#[derive(Serialize, Deserialize, Debug, PartialEq)]
852pub struct QubitHdr {
853 pub qubit_id: u16,
854}
855
856def_len!(QubitHdr, 2);
857
858/// # CQC Communication Header
859///
860/// Additional header used to send to which node to send information to. Used
861/// in send and EPR commands.
862///
863///
864/// ```text
865/// Field Length Meaning
866/// ----- ------ -------
867/// remote_app_id 2 bytes Remote application ID.
868/// remote_port 2 bytes Port of the remote node for sending classical
869/// control info.
870/// remote_node 4 bytes IP of the remote node (IPv4).
871/// ```
872#[derive(Serialize, Deserialize, Debug, PartialEq)]
873pub struct CommHdr {
874 pub remote_app_id: u16,
875 pub remote_port: u16,
876 pub remote_node: u32,
877}
878
879def_len!(CommHdr, 8);
880
881/// # CQC Factory Header
882///
883/// Additional header used to send factory information. Factory commands are
884/// used to tell the backend to do the following command or a sequence of
885/// commands multiple times.
886///
887/// ```text
888/// Field Length Meaning
889/// ----- ------ -------
890/// num_iter 1 byte Number of iterations to do the sequence.
891/// options 1 byte Options when executing the factory.
892/// ```
893#[derive(Serialize, Deserialize, Debug, PartialEq)]
894pub struct FactoryHdr {
895 pub num_iter: u8,
896 pub options: FactoryOpt,
897}
898
899def_len!(FactoryHdr, 2);
900
901bitflags! {
902 /// # CQC Factory Header options
903 ///
904 /// Factory options are set as bit flags.
905 ///
906 /// ```text
907 /// Flag Name Meaning
908 /// ---- ---- -------
909 /// 0x01 Notify Send a notification when command completes.
910 /// 0x04 Block Block until factory is done.
911 /// ```
912 pub struct FactoryOpt: u8 {
913 const NOTIFY = 0x01;
914 const BLOCK = 0x04;
915 }
916}
917
918impl FactoryOpt {
919 def_set_flag!(FactoryOpt, NOTIFY, set_notify);
920 def_set_flag!(FactoryOpt, BLOCK, set_block);
921
922 def_get_flag!(FactoryOpt, NOTIFY, get_notify);
923 def_get_flag!(FactoryOpt, BLOCK, get_block);
924}
925
926serde_option_u8!(FactoryOpt, FactoryOptVisitor, "factory");
927
928/// # CQC Measurement Outcome Header
929///
930/// Additional header used to send the outcome of a measurement.
931///
932/// ```text
933/// Field Length Meaning
934/// ----- ------ -------
935/// meas_out 1 byte Measurement outcome.
936/// ```
937#[derive(Serialize, Deserialize, Debug, PartialEq)]
938pub struct MeasOutHdr {
939 pub meas_out: MeasOut,
940}
941
942def_len!(MeasOutHdr, 1);
943
944/// # CQC Measurement outcome
945///
946/// There are only two possible outcome values: 0 or 1.
947#[repr(u8)]
948#[derive(Copy, Clone, Debug, PartialEq)]
949pub enum MeasOut {
950 Zero = 0,
951 One = 1,
952}
953
954impl MeasOut {
955 /// Convert an 8-bit value to a measurement outcome value. Returns `None`
956 /// if the value does not correspond to a valid outcome.
957 #[inline]
958 pub fn get(value: u8) -> Option<MeasOut> {
959 let meas_out = match value {
960 0 => MeasOut::Zero,
961 1 => MeasOut::One,
962 _ => return None,
963 };
964
965 Some(meas_out)
966 }
967}
968
969serde_enum_u8!(MeasOut, MeasOutVisitor, "Measurement Outcome");
970
971/// # CQC Time Info Header
972///
973/// Additional header used to send time information in response to the GetTime
974/// command.
975///
976/// ```text
977/// Field Length Meaning
978/// ----- ------ -------
979/// datetime 8 bytes Time of creation.
980/// ```
981#[derive(Serialize, Deserialize, Debug, PartialEq)]
982pub struct TimeInfoHdr {
983 pub datetime: u64,
984}
985
986def_len!(TimeInfoHdr, 8);
987
988/// # CQC Entanglement Information Header
989///
990/// When an EPR-pair is created the CQC Backend will return information about
991/// the entanglement which can be used in a entanglement management protocol.
992/// The entanglement information header contains information about the parties
993/// that share the EPR-pair, the time of creation, how good the entanglement is
994/// (goodness). Furthermore, the entanglement information header contain a
995/// entanglement ID (id_AB) which can be used to keep track of the entanglement
996/// in the network. The entanglement ID is incremented with respect to the
997/// pair of nodes and who initialized the entanglement (DF). For this reason
998/// the entanglement ID together with the nodes and the directionality flag
999/// gives a unique way to identify the entanglement in the network.
1000///
1001/// ```text
1002/// Field Length Meaning
1003/// ----- ------ -------
1004/// node_A 4 bytes IP of this node.
1005/// port_A 2 bytes Port of this node.
1006/// app_id_A 2 bytes App ID of this node.
1007/// node_B 4 bytes IP of other node.
1008/// port_B 2 bytes Port of other node.
1009/// app_id_B 2 bytes App ID of other node.
1010/// id_AB 4 bytes Entanglement ID.
1011/// timestamp 8 bytes Time of creation.
1012/// ToG 8 bytes Time of goodness.
1013/// goodness 2 bytes Goodness (estimate of the fidelity of state).
1014/// DF 1 byte Directionality flag (0=Mid, 1=node_A, 2=node_B).
1015/// align 1 byte 4 byte alignment.
1016/// ```
1017#[derive(Serialize, Deserialize, Debug, PartialEq)]
1018pub struct EntInfoHdr {
1019 pub node_a: u32,
1020 pub port_a: u16,
1021 pub app_id_a: u16,
1022 pub node_b: u32,
1023 pub port_b: u16,
1024 pub app_id_b: u16,
1025 pub id_ab: u32,
1026 pub timestamp: u64,
1027 pub tog: u64,
1028 pub goodness: u16,
1029 pub df: u8,
1030 pub align: u8,
1031}
1032
1033def_len!(EntInfoHdr, 40);
1034
1035/// # CQC Type Header
1036///
1037/// A top-level CQC header of type Mix may be followed by multiple other header
1038/// types. Each new header is announced by the CQC type header.
1039///
1040/// ```text
1041/// Field Length Meaning
1042/// ----- ------ -------
1043/// type 1 byte Type of next header (except Mix).
1044/// length 4 bytes Number of bytes until the next type header.
1045/// ```
1046#[derive(Serialize, Deserialize, Debug, PartialEq)]
1047pub struct TypeHdr {
1048 pub hdr_type: Tp,
1049 pub length: u32,
1050}
1051
1052def_len!(TypeHdr, 5);
1053
1054/// # CQC If Header
1055///
1056/// The If header can only be used inside programs of type Mix. Execute the
1057/// following command only if the specified condition is true.
1058///
1059/// ```text
1060/// Field Length Meaning
1061/// ----- ------ -------
1062/// left_operand 4 bytes Refernce ID of the first operand.
1063/// operator 1 byte Comparison operator.
1064/// right_type 1 byte Type of second operand.
1065/// right_operand 4 bytes Reference ID or value of second operand.
1066/// length 4 bytes Length in bytes of following command.
1067/// ```
1068#[derive(Serialize, Deserialize, Debug, PartialEq)]
1069pub struct IfHdr {
1070 pub left_op: u32,
1071 pub operator: CmpType,
1072 pub right_op_t: OpType,
1073 pub right_op: u32,
1074 pub length: u32,
1075}
1076
1077def_len!(IfHdr, 14);
1078
1079/// ## CQC If Header Operator Types
1080///
1081/// ```text
1082/// Type Name Meaning
1083/// ---- ---- -------
1084/// 0 Eq Compare for equality.
1085/// 1 InEq Compare for inequality.
1086/// ```
1087#[repr(u8)]
1088#[derive(Copy, Clone, Debug, PartialEq)]
1089pub enum CmpType {
1090 Eq = 0,
1091 InEq = 1,
1092}
1093
1094impl CmpType {
1095 /// Convert an 8-bit value to a comparison operator type. Returns `None`
1096 /// if the value does not correspond to a valid operator type.
1097 #[inline]
1098 pub fn get(value: u8) -> Option<CmpType> {
1099 let cmp_type = match value {
1100 0 => CmpType::Eq,
1101 1 => CmpType::InEq,
1102 _ => return None,
1103 };
1104
1105 Some(cmp_type)
1106 }
1107}
1108
1109serde_enum_u8!(CmpType, CmpTypeVisitor, "Comparison Operator Type");
1110
1111/// ## CQC If Header Right Operand Types
1112///
1113/// ```text
1114/// Type Name Meaning
1115/// ---- ---- -------
1116/// 0 Value Right operand holds raw value.
1117/// 1 RefId Right operand holds reference ID.
1118/// ```
1119#[repr(u8)]
1120#[derive(Copy, Clone, Debug, PartialEq)]
1121pub enum OpType {
1122 Value = 0,
1123 RefId = 1,
1124}
1125
1126impl OpType {
1127 /// Convert an 8-bit value to an operand type. Returns `None` if the value
1128 /// does not correspond to a valid operand type.
1129 #[inline]
1130 pub fn get(value: u8) -> Option<OpType> {
1131 let op_type = match value {
1132 0 => OpType::Value,
1133 1 => OpType::RefId,
1134 _ => return None,
1135 };
1136
1137 Some(op_type)
1138 }
1139}
1140
1141serde_enum_u8!(OpType, OpTypeVisitor, "Operand Type");
1142
1143// ----------------------------------------------------------------------------
1144// Tests.
1145// ----------------------------------------------------------------------------
1146
1147#[cfg(test)]
1148mod tests {
1149 extern crate bincode;
1150
1151 use self::bincode::serialize;
1152 use super::*;
1153
1154 #[test]
1155 fn cqc_hdr_ser_size() {
1156 let cqc_hdr = CqcHdr {
1157 version: Version::V2,
1158 msg_type: MsgType::Tp(Tp::Hello),
1159 app_id: 0,
1160 length: 0,
1161 };
1162 assert_eq!(serialize(&cqc_hdr).unwrap().len() as u32, cqc_hdr.len());
1163 }
1164
1165 #[test]
1166 fn cmd_hdr_ser_size() {
1167 let cmd_hdr = CmdHdr {
1168 qubit_id: 0,
1169 instr: Cmd::I,
1170 options: CmdOpt::empty(),
1171 };
1172 assert_eq!(serialize(&cmd_hdr).unwrap().len() as u32, cmd_hdr.len());
1173 }
1174
1175 #[test]
1176 fn assign_hdr_ser_size() {
1177 let assign_hdr = AssignHdr { ref_id: 0 };
1178 assert_eq!(
1179 serialize(&assign_hdr).unwrap().len() as u32,
1180 assign_hdr.len()
1181 );
1182 }
1183
1184 #[test]
1185 fn rot_hdr_ser_size() {
1186 let rot_hdr = RotHdr { step: 0 };
1187 assert_eq!(serialize(&rot_hdr).unwrap().len() as u32, rot_hdr.len());
1188 }
1189
1190 #[test]
1191 fn qubit_hdr_ser_size() {
1192 let qubit_hdr = QubitHdr { qubit_id: 0 };
1193 assert_eq!(
1194 serialize(&qubit_hdr).unwrap().len() as u32,
1195 qubit_hdr.len()
1196 );
1197 }
1198
1199 #[test]
1200 fn comm_hdr_ser_size() {
1201 let comm_hdr = CommHdr {
1202 remote_app_id: 0,
1203 remote_node: 0,
1204 remote_port: 0,
1205 };
1206 assert_eq!(serialize(&comm_hdr).unwrap().len() as u32, comm_hdr.len());
1207 }
1208
1209 #[test]
1210 fn factory_hdr_ser_size() {
1211 let factory_hdr = FactoryHdr {
1212 num_iter: 0,
1213 options: FactoryOpt::empty(),
1214 };
1215 assert_eq!(
1216 serialize(&factory_hdr).unwrap().len() as u32,
1217 factory_hdr.len()
1218 );
1219 }
1220
1221 #[test]
1222 fn meas_out_hdr_ser_size() {
1223 let meas_out_hdr = MeasOutHdr {
1224 meas_out: MeasOut::Zero,
1225 };
1226 assert_eq!(
1227 serialize(&meas_out_hdr).unwrap().len() as u32,
1228 meas_out_hdr.len()
1229 );
1230 }
1231
1232 #[test]
1233 fn time_info_hdr_ser_size() {
1234 let time_info_hdr = TimeInfoHdr { datetime: 0 };
1235 assert_eq!(
1236 serialize(&time_info_hdr).unwrap().len() as u32,
1237 time_info_hdr.len()
1238 );
1239 }
1240
1241 #[test]
1242 fn ent_info_hdr_ser_size() {
1243 let ent_info_hdr = EntInfoHdr {
1244 node_a: 0,
1245 port_a: 0,
1246 app_id_a: 0,
1247 node_b: 0,
1248 port_b: 0,
1249 app_id_b: 0,
1250 id_ab: 0,
1251 timestamp: 0,
1252 tog: 0,
1253 goodness: 0,
1254 df: 0,
1255 align: 0,
1256 };
1257 assert_eq!(
1258 serialize(&ent_info_hdr).unwrap().len() as u32,
1259 ent_info_hdr.len()
1260 );
1261 }
1262
1263 #[test]
1264 fn type_hdr_ser_size() {
1265 let type_hdr = TypeHdr {
1266 hdr_type: Tp::Hello,
1267 length: 0,
1268 };
1269 assert_eq!(serialize(&type_hdr).unwrap().len() as u32, type_hdr.len());
1270 }
1271
1272 #[test]
1273 fn if_hdr_ser_size() {
1274 let if_hdr = IfHdr {
1275 left_op: 0,
1276 operator: CmpType::Eq,
1277 right_op_t: OpType::Value,
1278 right_op: 0,
1279 length: 0,
1280 };
1281 assert_eq!(serialize(&if_hdr).unwrap().len() as u32, if_hdr.len());
1282 }
1283}