2021-11-24 17:57:14 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2021 Fluence Labs Limited
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2022-10-09 12:56:12 +03:00
|
|
|
mod stream_descriptor;
|
|
|
|
mod stream_value_descriptor;
|
|
|
|
mod utils;
|
|
|
|
|
2021-11-24 17:57:14 +03:00
|
|
|
use crate::execution_step::ExecutionResult;
|
|
|
|
use crate::execution_step::Stream;
|
2022-10-12 04:29:31 +03:00
|
|
|
use crate::ExecutionError;
|
2023-04-10 14:07:50 +03:00
|
|
|
|
2022-10-09 12:56:12 +03:00
|
|
|
use stream_descriptor::*;
|
|
|
|
pub(crate) use stream_value_descriptor::StreamValueDescriptor;
|
2021-11-24 17:57:14 +03:00
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
use air_interpreter_data::GenerationIdx;
|
2021-11-24 17:57:14 +03:00
|
|
|
use air_interpreter_data::GlobalStreamGens;
|
|
|
|
use air_interpreter_data::RestrictedStreamGens;
|
2022-10-09 12:56:12 +03:00
|
|
|
use air_parser::ast::Span;
|
2022-09-29 00:16:37 +03:00
|
|
|
use air_parser::AirPos;
|
2022-10-12 04:29:31 +03:00
|
|
|
use air_trace_handler::TraceHandler;
|
2021-11-24 17:57:14 +03:00
|
|
|
|
|
|
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct Streams {
|
|
|
|
// this one is optimized for speed (not for memory), because it's unexpected
|
|
|
|
// that a script could have a lot of new.
|
|
|
|
// TODO: use shared string (Rc<String>) to avoid copying.
|
|
|
|
streams: HashMap<String, Vec<StreamDescriptor>>,
|
|
|
|
|
2022-10-09 12:56:12 +03:00
|
|
|
/// Contains stream generations from previous data that a restricted stream
|
|
|
|
/// should have at the scope start.
|
|
|
|
previous_restricted_stream_gens: RestrictedStreamGens,
|
|
|
|
|
2022-10-12 04:29:31 +03:00
|
|
|
/// Contains stream generations from current data that a restricted stream
|
|
|
|
/// should have at the scope start.
|
|
|
|
current_restricted_stream_gens: RestrictedStreamGens,
|
|
|
|
|
2021-11-24 17:57:14 +03:00
|
|
|
/// Contains stream generations that each private stream had at the scope end.
|
|
|
|
/// Then it's placed into data
|
2022-10-09 12:56:12 +03:00
|
|
|
new_restricted_stream_gens: RestrictedStreamGens,
|
2021-11-24 17:57:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Streams {
|
2022-09-05 17:57:26 +03:00
|
|
|
pub(crate) fn from_data(
|
2022-12-26 15:45:14 +07:00
|
|
|
previous_global_streams: GlobalStreamGens,
|
|
|
|
current_global_streams: GlobalStreamGens,
|
2022-10-09 12:56:12 +03:00
|
|
|
previous_restricted_stream_gens: RestrictedStreamGens,
|
2022-10-12 04:29:31 +03:00
|
|
|
current_restricted_stream_gens: RestrictedStreamGens,
|
2022-09-05 17:57:26 +03:00
|
|
|
) -> Self {
|
2022-10-12 04:29:31 +03:00
|
|
|
let streams = utils::merge_global_streams(previous_global_streams, current_global_streams);
|
2022-09-05 17:57:26 +03:00
|
|
|
|
|
|
|
Self {
|
2022-10-09 12:56:12 +03:00
|
|
|
streams,
|
|
|
|
previous_restricted_stream_gens,
|
2022-10-12 04:29:31 +03:00
|
|
|
current_restricted_stream_gens,
|
2022-10-09 12:56:12 +03:00
|
|
|
new_restricted_stream_gens: <_>::default(),
|
2022-09-05 17:57:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-29 00:16:37 +03:00
|
|
|
pub(crate) fn get(&self, name: &str, position: AirPos) -> Option<&Stream> {
|
2021-11-24 17:57:14 +03:00
|
|
|
self.streams
|
|
|
|
.get(name)
|
2022-02-16 23:34:15 +03:00
|
|
|
.and_then(|descriptors| find_closest(descriptors.iter(), position))
|
2021-11-24 17:57:14 +03:00
|
|
|
}
|
|
|
|
|
2022-09-29 00:16:37 +03:00
|
|
|
pub(crate) fn get_mut(&mut self, name: &str, position: AirPos) -> Option<&mut Stream> {
|
2022-03-03 19:09:48 +03:00
|
|
|
self.streams
|
|
|
|
.get_mut(name)
|
|
|
|
.and_then(|descriptors| find_closest_mut(descriptors.iter_mut(), position))
|
|
|
|
}
|
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
pub(crate) fn add_stream_value(
|
|
|
|
&mut self,
|
|
|
|
value_descriptor: StreamValueDescriptor<'_>,
|
|
|
|
) -> ExecutionResult<GenerationIdx> {
|
2022-10-09 12:56:12 +03:00
|
|
|
let StreamValueDescriptor {
|
|
|
|
value,
|
|
|
|
name,
|
|
|
|
source,
|
|
|
|
generation,
|
|
|
|
position,
|
|
|
|
} = value_descriptor;
|
|
|
|
|
|
|
|
match self.get_mut(name, position) {
|
|
|
|
Some(stream) => stream.add_value(value, generation, source),
|
2021-11-24 17:57:14 +03:00
|
|
|
None => {
|
|
|
|
// streams could be created in three ways:
|
|
|
|
// - after met new instruction with stream name that isn't present in streams
|
|
|
|
// (it's the only way to create restricted streams)
|
|
|
|
// - by calling add_global_stream with generation that come from data
|
|
|
|
// for global streams
|
|
|
|
// - and by this function, and if there is no such a streams in streams,
|
|
|
|
// it means that a new global one should be created.
|
|
|
|
let stream = Stream::from_value(value);
|
2022-09-05 17:57:26 +03:00
|
|
|
let descriptor = StreamDescriptor::global(stream);
|
2022-10-09 12:56:12 +03:00
|
|
|
self.streams.insert(name.to_string(), vec![descriptor]);
|
2021-11-24 17:57:14 +03:00
|
|
|
let generation = 0;
|
2023-04-10 14:07:50 +03:00
|
|
|
Ok(generation.into())
|
2021-11-24 17:57:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
pub(crate) fn meet_scope_start(&mut self, name: impl Into<String>, span: Span, iteration: usize) {
|
2021-11-24 17:57:14 +03:00
|
|
|
let name = name.into();
|
2023-04-10 14:07:50 +03:00
|
|
|
let (prev_gens_count, current_gens_count) = self.stream_generation_from_data(&name, span.left, iteration);
|
2021-11-24 17:57:14 +03:00
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
let new_stream = Stream::from_generations_count(prev_gens_count, current_gens_count);
|
2021-11-24 17:57:14 +03:00
|
|
|
let new_descriptor = StreamDescriptor::restricted(new_stream, span);
|
|
|
|
match self.streams.entry(name) {
|
|
|
|
Occupied(mut entry) => {
|
|
|
|
entry.get_mut().push(new_descriptor);
|
|
|
|
}
|
|
|
|
Vacant(entry) => {
|
|
|
|
entry.insert(vec![new_descriptor]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 04:29:31 +03:00
|
|
|
pub(crate) fn meet_scope_end(
|
|
|
|
&mut self,
|
|
|
|
name: String,
|
|
|
|
position: AirPos,
|
|
|
|
trace_ctx: &mut TraceHandler,
|
|
|
|
) -> ExecutionResult<()> {
|
2021-11-24 17:57:14 +03:00
|
|
|
// unwraps are safe here because met_scope_end must be called after met_scope_start
|
|
|
|
let stream_descriptors = self.streams.get_mut(&name).unwrap();
|
|
|
|
// delete a stream after exit from a scope
|
|
|
|
let last_descriptor = stream_descriptors.pop().unwrap();
|
|
|
|
if stream_descriptors.is_empty() {
|
|
|
|
// streams should contain only non-empty stream embodiments
|
|
|
|
self.streams.remove(&name);
|
|
|
|
}
|
2022-10-12 04:29:31 +03:00
|
|
|
let gens_count = last_descriptor.stream.compactify(trace_ctx)?;
|
2021-11-24 17:57:14 +03:00
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
self.collect_stream_generation(name, position, gens_count);
|
2022-10-09 12:56:12 +03:00
|
|
|
Ok(())
|
2021-11-24 17:57:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This method must be called at the end of execution, because it contains logic to collect
|
|
|
|
/// all global streams depending on their presence in a streams field.
|
2022-10-12 04:29:31 +03:00
|
|
|
pub(crate) fn into_streams_data(
|
|
|
|
self,
|
|
|
|
trace_ctx: &mut TraceHandler,
|
|
|
|
) -> ExecutionResult<(GlobalStreamGens, RestrictedStreamGens)> {
|
2021-11-24 17:57:14 +03:00
|
|
|
// since it's called at the end of execution, streams contains only global ones,
|
|
|
|
// because all private's been deleted after exiting a scope
|
|
|
|
let global_streams = self
|
|
|
|
.streams
|
|
|
|
.into_iter()
|
2022-10-12 04:29:31 +03:00
|
|
|
.map(|(name, mut descriptors)| -> Result<_, ExecutionError> {
|
2021-11-24 17:57:14 +03:00
|
|
|
// unwrap is safe here because of invariant that streams contains non-empty vectors,
|
|
|
|
// moreover it must contain only one value, because this method is called at the end
|
|
|
|
// of the execution
|
2022-10-09 12:56:12 +03:00
|
|
|
let stream = descriptors.pop().unwrap().stream;
|
2022-10-12 04:29:31 +03:00
|
|
|
let gens_count = stream.compactify(trace_ctx)?;
|
2023-04-10 14:07:50 +03:00
|
|
|
Ok((name, gens_count))
|
2021-11-24 17:57:14 +03:00
|
|
|
})
|
2022-10-12 04:29:31 +03:00
|
|
|
.collect::<Result<GlobalStreamGens, _>>()?;
|
|
|
|
|
|
|
|
Ok((global_streams, self.new_restricted_stream_gens))
|
|
|
|
}
|
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
fn stream_generation_from_data(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
|
|
|
position: AirPos,
|
|
|
|
iteration: usize,
|
|
|
|
) -> (GenerationIdx, GenerationIdx) {
|
2022-10-12 04:29:31 +03:00
|
|
|
let previous_generation =
|
|
|
|
Self::restricted_stream_generation(&self.previous_restricted_stream_gens, name, position, iteration)
|
|
|
|
.unwrap_or_default();
|
|
|
|
let current_generation =
|
|
|
|
Self::restricted_stream_generation(&self.current_restricted_stream_gens, name, position, iteration)
|
|
|
|
.unwrap_or_default();
|
2022-10-09 12:56:12 +03:00
|
|
|
|
2022-10-12 04:29:31 +03:00
|
|
|
(previous_generation, current_generation)
|
2022-10-09 12:56:12 +03:00
|
|
|
}
|
|
|
|
|
2022-10-12 04:29:31 +03:00
|
|
|
fn restricted_stream_generation(
|
|
|
|
restricted_stream_gens: &RestrictedStreamGens,
|
|
|
|
name: &str,
|
|
|
|
position: AirPos,
|
|
|
|
iteration: usize,
|
2023-04-10 14:07:50 +03:00
|
|
|
) -> Option<GenerationIdx> {
|
2022-10-12 04:29:31 +03:00
|
|
|
restricted_stream_gens
|
2021-11-24 17:57:14 +03:00
|
|
|
.get(name)
|
2022-02-16 23:34:15 +03:00
|
|
|
.and_then(|scopes| scopes.get(&position).and_then(|iterations| iterations.get(iteration)))
|
2021-11-24 17:57:14 +03:00
|
|
|
.copied()
|
|
|
|
}
|
|
|
|
|
2023-04-10 14:07:50 +03:00
|
|
|
fn collect_stream_generation(&mut self, name: String, position: AirPos, generation: GenerationIdx) {
|
2022-10-09 12:56:12 +03:00
|
|
|
match self.new_restricted_stream_gens.entry(name) {
|
2021-11-24 17:57:14 +03:00
|
|
|
Occupied(mut streams) => match streams.get_mut().entry(position) {
|
|
|
|
Occupied(mut iterations) => iterations.get_mut().push(generation),
|
|
|
|
Vacant(entry) => {
|
|
|
|
entry.insert(vec![generation]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Vacant(entry) => {
|
|
|
|
let iterations = maplit::hashmap! {
|
|
|
|
position => vec![generation],
|
|
|
|
};
|
|
|
|
entry.insert(iterations);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
impl fmt::Display for Streams {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
for (name, descriptors) in self.streams.iter() {
|
|
|
|
if let Some(last_descriptor) = descriptors.last() {
|
2022-12-12 22:37:05 +07:00
|
|
|
writeln!(f, "{name} => {last_descriptor}")?;
|
2021-11-24 17:57:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|