quil_rs/
quil.rs

1/// A trait to wrap items which represent some construct within the Quil language.
2///
3/// If you want to serialize an object to string and fail if it can't be represented as valid Quil, then use
4/// `to_quil()`. If you want to serialize an object to string infallibly, and can tolerate invalid Quil, then
5/// use `to_quil_or_debug()`.
6pub trait Quil: std::fmt::Debug {
7    /// Return a string in valid Quil syntax or an error if the item cannot be represented with valid Quil.
8    fn to_quil(&self) -> Result<String, ToQuilError> {
9        let mut buffer = String::new();
10        self.write(&mut buffer, false)?;
11        Ok(buffer)
12    }
13
14    /// Return a string in valid Quil syntax if possible. Any individual component of this object
15    /// which cannot be represented in Quil will be replaced with a `Debug` representation of that
16    /// component.
17    fn to_quil_or_debug(&self) -> String {
18        let mut buffer = String::new();
19        let _ = self.write(&mut buffer, true);
20        buffer
21    }
22
23    /// Write the Quil representation of the item to the given writer. If `fall_back_to_debug`
24    /// is `true`, then it must not return an error.
25    fn write(
26        &self,
27        writer: &mut impl std::fmt::Write,
28        fall_back_to_debug: bool,
29    ) -> Result<(), ToQuilError>;
30}
31
32/// Per the Quil specification, an indentation is exactly 4 spaces.
33/// See [Quil 3-2](https://quil-lang.github.io/#3-2Syntactic-Rudiments)
34pub(crate) const INDENT: &str = "    ";
35
36pub type ToQuilResult<T> = Result<T, ToQuilError>;
37
38/// Errors which can occur when converting a Quil item to a string.
39#[derive(Debug, thiserror::Error, PartialEq)]
40#[non_exhaustive]
41pub enum ToQuilError {
42    #[error("Failed to write Quil: {0}")]
43    FormatError(#[from] std::fmt::Error),
44    #[error("Label has not yet been resolved")]
45    UnresolvedLabelPlaceholder,
46    #[error("Qubit has not yet been resolved")]
47    UnresolvedQubitPlaceholder,
48}
49
50/// Write an iterator of Quil items to the given writer, joined with the provided `joiner`.
51pub(crate) fn write_join_quil<'i, I, T>(
52    writer: &mut impl std::fmt::Write,
53    fall_back_to_debug: bool,
54    values: I,
55    joiner: &str,
56    prefix: &str,
57) -> Result<(), ToQuilError>
58where
59    I: IntoIterator<Item = &'i T>,
60    T: Quil + 'i,
61{
62    let mut iter = values.into_iter();
63    if let Some(first) = iter.next() {
64        write!(writer, "{prefix}")?;
65        first.write(writer, fall_back_to_debug)?;
66
67        for value in iter {
68            write!(writer, "{joiner}{prefix}")?;
69            value.write(writer, fall_back_to_debug)?;
70        }
71    }
72    Ok(())
73}