1use crate::{
2 aim::{Context, WorkflowLike, Workspace, Writer, WriterLike},
3 expressions::Reference, reference::parse_reference,
4};
5use std::{
6 fmt,
7 sync::{Arc, RwLock}
8};
9use anyhow::Result;
10use nom::{
11 IResult, Parser,
12 character::complete::{char, multispace0},
13 sequence::{delimited, preceded},
14};
15
16#[derive(Debug, Clone)]
17enum InstanceState {
18 Unloaded { source: Arc<Reference>, target: Arc<Reference> },
20 Loaded { context: Arc<RwLock<Context>> },
22}
23
24#[derive(Debug, Clone)]
25pub struct Instance {
26 inner: Arc<RwLock<InstanceState>>,
28}
29
30impl Instance {
31 pub fn new( source: Arc<Reference>, target: Arc<Reference>) -> Self {
32 Instance {
33 inner: Arc::new(RwLock::new(InstanceState::Unloaded {
34 source,
35 target,
36 })),
37 }
38 }
39pub fn locate(handle: &str) -> Result<Arc<RwLock<Context>>> {
65 let locator = Reference::context();
66 let instance = Workspace::locate_instance(&locator, handle)?;
67 instance.get_context_lock()
68 }
69
70 pub fn get_context_lock(&self) -> Result<Arc<RwLock<Context>>> {
71 let read_guard = self.inner.read()
73 .expect("Lock poisoned in get_context_lock() instance read.");
74
75 match &*read_guard {
76 InstanceState::Loaded { context } => {
77 Ok(context.clone())
78 }
79 InstanceState::Unloaded { source: _, target: _} => {
80 drop(read_guard);
82
83 let mut write_guard = self.inner.write()
85 .expect("Lock poisoned in get_context_lock() instance write.");
86
87 match &*write_guard {
89 InstanceState::Loaded { context } => {
90 Ok(context.clone())
91 }
92 InstanceState::Unloaded { source, target } => {
93 let ctx = Context::open(source.clone(), target.clone())?;
95 let context = Arc::new(RwLock::new(ctx));
96
97 *write_guard = InstanceState::Loaded {
99 context: context.clone(),
100 };
101
102 Ok(context)
103 }
104 }
105 }
106 }
107 }
108
109 pub fn compact(&self) {
110 let read_guard = self.inner.read()
112 .expect("Lock poisoned in compact() instance read.");
113
114 if let InstanceState::Loaded { context: _ } = &*read_guard {
115 drop(read_guard);
116 let mut write_guard = self.inner.write()
117 .expect("Lock poisoned in compact() instance write.");
118
119 if let InstanceState::Loaded { context } = &*write_guard {
121 let rwlock_context = context.clone();
122 let mut context_guard = rwlock_context.write()
123
124 .expect("Lock poisoned in compact() context write.");
125 if !context_guard.target().is_touched() {
126 let source = context_guard.source().locator();
127 let target = context_guard.target().locator();
128 *write_guard = InstanceState::Unloaded { source, target };
130 }
131 }
132 }
133 }
134
135 pub fn save_all(&self) -> Result<()> {
137 let read_guard = self.inner.read()
139 .expect("Lock poisoned in save_all() instance read.");
140
141 match &*read_guard {
142 InstanceState::Loaded { context } => {
143 let mut write_guard = context.write()
144 .expect("Lock poisoned in save_all() context write.");
145 write_guard.save_all()
146 }
147 _ => Ok(()),
149 }
150 }
151
152 pub fn print(&self, writer: &mut Writer) {
153 let read_guard = self.inner.read()
154 .expect("Lock poisoned in print() instance read.");
155 match &*read_guard {
156 InstanceState::Loaded { context } => {
157 let context_guard = context.read()
158 .expect("Lock poisoned in print() context read.");
159 context_guard.print(writer);
160 }
161 InstanceState::Unloaded { source, target} => {
162 source.print(writer);
163 writer.write_str(", ");
164 target.print(writer);
165 }
166 }
167 }
168}
169
170pub fn parse_instance(input: &str) -> IResult<&str, Instance> {
171 let (input, (source, target)) = delimited(
172 multispace0,
173 (
175 parse_reference,
176 preceded(
177 (multispace0, char(','), multispace0),
178 parse_reference,
179 ),
180 ),
181 multispace0,
182 ).parse(input)?;
183
184 Ok((input, Instance::new(source, target)))
185}
186
187impl PartialEq for Instance {
188 fn eq(&self, other: &Self) -> bool {
190 Arc::ptr_eq(&self.inner, &other.inner)
191 }
192}
193
194impl WriterLike for Instance {
195 fn write(&self, writer: &mut Writer) {
196 self.print(writer);
197 }
198}
199
200impl fmt::Display for Instance {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "{}", self.to_stringized())
203 }
204}