1mod context;
2
3use std::fs::{File, OpenOptions};
4use std::io;
5use std::path::Path;
6
7pub use context::DecoderContext;
8use msgpacker::Message;
9
10use crate::{Constraint, DecodableElement, Preamble, Witness};
11
12#[derive(Debug, Clone)]
17pub struct CircuitDescription<S> {
18 preamble: Preamble,
19 source_names: Vec<String>,
20 source_contents: Vec<String>,
21 source: S,
22}
23
24impl<S> CircuitDescription<S> {
25 pub(crate) fn context(&mut self) -> (DecoderContext, &mut S) {
26 let Self {
27 preamble,
28 source_names,
29 source_contents,
30 source,
31 } = self;
32
33 let ctx = DecoderContext::new(&preamble.config, source_names, source_contents);
34
35 (ctx, source)
36 }
37
38 pub const fn preamble(&self) -> &Preamble {
40 &self.preamble
41 }
42
43 pub fn source_name_contains(&self, name: &str) -> bool {
45 self.source_names.iter().any(|n| n.contains(name))
46 }
47}
48
49impl CircuitDescription<File> {
50 pub fn open<P>(path: P) -> io::Result<Self>
52 where
53 P: AsRef<Path>,
54 {
55 OpenOptions::new()
56 .read(true)
57 .open(path)
58 .and_then(Self::from_reader)
59 }
60}
61
62impl<S> CircuitDescription<S>
63where
64 S: io::Read + io::Seek,
65{
66 pub fn from_reader(mut source: S) -> io::Result<Self> {
68 source.seek(io::SeekFrom::Start(0))?;
70
71 let preamble = Preamble::try_from_reader(&DecoderContext::BASE, source.by_ref())?;
73
74 let ofs = preamble.source_cache_offset();
75 let ofs = io::SeekFrom::Start(ofs as u64);
76 source.seek(ofs)?;
77
78 let source_names = Message::unpack(source.by_ref())?;
79 let source_contents = Message::unpack(source.by_ref())?;
80
81 let (source_names, source_contents) = match (source_names, source_contents) {
82 (Message::Array(n), Message::Array(c)) => (n, c),
83 _ => {
84 return Err(io::Error::new(
85 io::ErrorKind::InvalidData,
86 "the source cache isn't a valid array",
87 ))
88 }
89 };
90
91 let source_names = source_names
92 .into_iter()
93 .map(|m| match m {
94 Message::String(s) => Ok(s),
95 _ => Err(io::Error::new(
96 io::ErrorKind::InvalidData,
97 "the source names isn't composed of strings",
98 )),
99 })
100 .collect::<io::Result<Vec<_>>>()?;
101
102 let source_contents = source_contents
103 .into_iter()
104 .map(|m| match m {
105 Message::String(s) => Ok(s),
106 _ => Err(io::Error::new(
107 io::ErrorKind::InvalidData,
108 "the source contents isn't composed of strings",
109 )),
110 })
111 .collect::<io::Result<Vec<_>>>()?;
112
113 Ok(Self {
114 preamble,
115 source_names,
116 source_contents,
117 source,
118 })
119 }
120
121 pub fn fetch_constraint(&mut self, idx: usize) -> io::Result<Constraint> {
123 self.preamble
124 .constraint_offset(idx)
125 .ok_or_else(|| {
126 io::Error::new(io::ErrorKind::Other, "attempt to fetch invalid constraint")
127 })
128 .map(|ofs| io::SeekFrom::Start(ofs as u64))
129 .and_then(|ofs| self.source.seek(ofs))?;
130
131 let (ctx, source) = self.context();
132
133 Constraint::try_from_reader(&ctx, source)
134 }
135
136 pub fn fetch_witness(&mut self, idx: usize) -> io::Result<Witness> {
138 self.preamble
139 .witness_offset(idx)
140 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "attempt to fetch invalid witness"))
141 .map(|ofs| io::SeekFrom::Start(ofs as u64))
142 .and_then(|ofs| self.source.seek(ofs))?;
143
144 let (ctx, source) = self.context();
145
146 Witness::try_from_reader(&ctx, source)
147 }
148}