use std::collections::{HashMap, HashSet, BTreeMap};
use std::vec::Vec;
use std::fmt::{Formatter, Result, Display};
use std::hash::{Hash, Hasher};
use std::cmp::Ordering;
use crate::svg_generator::{
svg_frontend::timeline_panel::TimelineColumnData,
hover_messages,
};
pub static LINE_SPACE: i64 = 30;
pub trait Visualizable {
fn compute_branch_states(&self, history: & mut Vec<(usize, Event)>,
states: &mut Vec<(usize, usize, State)>,
hash: &u64,
valid_range: (usize, usize),
branch_start: usize,
branch_end: usize,
previous_state: State) -> State;
fn compute_timeline_states(&self, history: & mut Vec<(usize, Event)>, states: &mut Vec<(usize, usize, State)>, hash: &u64);
fn compute_states(&mut self);
fn append_decl_branch_events(&mut self, b_history: &Vec<(usize, ExternalEvent)>);
fn append_branch_event(&self, event: &ExternalEvent, line_number: usize, is: &ResourceTy, b_history: &mut Vec<(usize, Event)>);
fn event_of_exteranl_event(&self, line_num: usize, ext_ev: &ExternalEvent, to_o: bool) -> Vec<(usize, Event)>;
fn get_name_from_hash(&self, hash: &u64) -> Option<String>;
fn _append_event(&mut self, resource_access_point: &ResourceAccessPoint, event: Event, line_number: &usize);
fn append_processed_external_event(&mut self, event: ExternalEvent, line_number: usize);
fn is_mut(&self, hash: &u64 ) -> bool;
fn is_mutref(&self, hash: &u64) -> bool;
fn is_ref(&self, hash: &u64) -> bool;
fn calc_state(&self, previous_state: & State, event: & Event, event_line: usize, hash: &u64) -> State;
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub enum ResourceAccessPoint {
Owner(Owner),
MutRef(MutRef),
StaticRef(StaticRef),
Function(Function),
Struct(Struct),
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Owner {
pub name: String,
pub hash: u64,
pub is_mut: bool, pub is_copy: bool,
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Struct {
pub name: String,
pub hash: u64,
pub owner: u64,
pub is_mut: bool,
pub is_member: bool,
pub is_copy: bool,
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct MutRef { pub name: String,
pub hash: u64,
pub is_mut: bool,
pub member_of: Option<u64>,
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct StaticRef { pub name: String,
pub hash: u64,
pub is_mut: bool,
pub member_of: Option<u64>,
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Function {
pub name: String,
pub hash: u64,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ResourceTy {
Anonymous, Deref(ResourceAccessPoint), Caller, Value(ResourceAccessPoint)
}
impl ResourceTy {
pub fn name(&self) -> String {
match self {
ResourceTy::Anonymous => "Anonymous resource".to_owned(),
ResourceTy::Value(r) => r.name().to_owned(),
ResourceTy::Deref(r) => format!("*{}", r.name()),
ResourceTy::Caller => "Caller".to_owned()
}
}
pub fn real_name(&self) -> String {
match self {
ResourceTy::Anonymous => "Anonymous resource".to_owned(),
ResourceTy::Value(r) | ResourceTy::Deref(r) => r.name().to_owned(),
ResourceTy::Caller => "Caller".to_owned()
}
}
pub fn hash(&self) -> &u64 {
match self {
ResourceTy::Caller | ResourceTy::Anonymous => &std::u64::MAX,
ResourceTy::Value(r) | ResourceTy::Deref(r) => r.hash(),
}
}
pub fn is_ref(&self) -> bool {
match self {
ResourceTy::Value(r) | ResourceTy::Deref(r) => r.is_ref(),
_ => false
}
}
pub fn is_mutref(&self) -> bool {
match self {
ResourceTy::Value(r) | ResourceTy::Deref(r) => r.is_mutref(),
_ => false
}
}
pub fn extract_rap(&self) -> Option<&ResourceAccessPoint> {
match self {
ResourceTy::Anonymous | ResourceTy::Caller => None,
ResourceTy::Deref(r) | ResourceTy::Value(r) => Some(r)
}
}
pub fn is_same_underlying(&self, other: &ResourceTy) -> bool{
match (self.extract_rap(), other.extract_rap()) {
(Some(r), Some(o)) => {
r.hash() == o.hash()
}
_ => false
}
}
}
impl Hash for ResourceTy {
fn hash<H: Hasher>(&self, state: &mut H) {
self.real_name().hash(state);
}
}
impl ResourceAccessPoint {
pub fn hash(&self) -> &u64 {
match self {
ResourceAccessPoint::Owner(Owner{hash, ..}) => hash,
ResourceAccessPoint::Struct(Struct{hash, ..}) => hash,
ResourceAccessPoint::MutRef(MutRef{hash, ..}) => hash,
ResourceAccessPoint::StaticRef(StaticRef{hash, ..}) => hash,
ResourceAccessPoint::Function(Function{hash, ..}) => hash,
}
}
pub fn name(&self) -> &String {
match self {
ResourceAccessPoint::Owner(Owner{name, ..}) => name,
ResourceAccessPoint::Struct(Struct{name, ..}) => name,
ResourceAccessPoint::MutRef(MutRef{name, ..}) => name,
ResourceAccessPoint::StaticRef(StaticRef{name, ..}) => name,
ResourceAccessPoint::Function(Function{name, ..}) => name,
}
}
pub fn is_mut(&self) -> bool {
match self {
ResourceAccessPoint::Owner(Owner{is_mut, ..}) => *is_mut,
ResourceAccessPoint::Struct(Struct{is_mut, ..}) => *is_mut,
ResourceAccessPoint::MutRef(MutRef{is_mut, ..}) => *is_mut,
ResourceAccessPoint::StaticRef(StaticRef{is_mut, ..}) => *is_mut,
ResourceAccessPoint::Function(_) => false,
}
}
pub fn is_ref(&self) -> bool {
match self {
ResourceAccessPoint::MutRef(_) | ResourceAccessPoint::StaticRef(_) => true,
_ => false
}
}
pub fn is_copy(&self) -> bool {
match self {
ResourceAccessPoint::Owner(Owner{is_copy, ..}) => *is_copy,
ResourceAccessPoint::Struct(Struct{is_copy, ..}) => *is_copy,
ResourceAccessPoint::MutRef(_) | ResourceAccessPoint::StaticRef(_) => true,
ResourceAccessPoint::Function(_) => true,
}
}
pub fn is_mutref(&self) -> bool {
match self {
ResourceAccessPoint::MutRef(_) => true,
_ => false
}
}
pub fn is_struct_group(&self) -> bool {
match self {
ResourceAccessPoint::Struct(_) => true,
ResourceAccessPoint::MutRef(MutRef{member_of: Some(_), ..})
| ResourceAccessPoint::StaticRef(StaticRef{member_of: Some(_), ..}) => true,
_ => false,
}
}
pub fn is_struct(&self) -> bool {
match self {
ResourceAccessPoint::Struct(Struct{is_member, ..}) => !is_member,
_ => false
}
}
pub fn is_member(&self) -> bool {
match self {
ResourceAccessPoint::Struct(Struct{is_member, ..}) => *is_member,
ResourceAccessPoint::MutRef(MutRef{member_of, ..})
| ResourceAccessPoint::StaticRef(StaticRef{member_of, ..}) => member_of.is_some(),
_ => false,
}
}
pub fn get_owner(&self) -> u64 {
match self {
ResourceAccessPoint::Owner(Owner{hash, ..}) => hash.to_owned(),
ResourceAccessPoint::Struct(Struct{owner, ..}) => owner.to_owned(),
ResourceAccessPoint::MutRef(MutRef{hash, member_of, ..}) =>
member_of.unwrap_or(*hash),
ResourceAccessPoint::StaticRef(StaticRef{hash, member_of, ..}) =>
member_of.unwrap_or(*hash),
ResourceAccessPoint::Function(Function{hash, ..}) => hash.to_owned(),
}
}
pub fn is_owner(&self) -> bool {
match self {
ResourceAccessPoint::Owner(_) => true,
_ => false
}
}
pub fn is_fn(&self) -> bool {
match self {
ResourceAccessPoint::Function(_) => true,
_ => false
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum BranchType {
If(Vec<String>, Vec<(usize, usize)>),
Loop(Vec<String>, Vec<(usize, usize)>),
Match(Vec<String>, Vec<(usize, usize)>)
}
impl BranchType {
pub fn get_start_end(&self, index: usize) -> (usize, usize) {
match self {
BranchType::If(_, v)
| BranchType::Loop(_, v)
| BranchType::Match(_, v) => {
v.get(index).unwrap().to_owned()
}
}
}
pub fn get_mut_start_end(& mut self, index: usize) -> & mut (usize, usize) {
match self {
BranchType::If(_, v)
| BranchType::Loop(_, v)
| BranchType::Match(_, v) => {
v.get_mut(index).unwrap()
}
}
}
pub fn string_of_branch(&self, index: usize) -> String {
match self {
BranchType::If(x, _) | BranchType::Loop(x, _) | BranchType::Match(x,_) => {
x.get(index).unwrap().clone()
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtBranchData {
pub e_data: Vec<(usize, ExternalEvent)>,
pub line_map: BTreeMap<usize, Vec<ExternalEvent>>,
pub decl_vars: HashSet<ResourceAccessPoint>
}
pub fn string_of_branch(b: &BranchType, index: usize) -> String {
match b {
BranchType::If(x, _) | BranchType::Loop(x, _) | BranchType::Match(x,_) => {
x.get(index).unwrap().clone()
}
}
}
pub fn create_line_map(v: &Vec<(usize, ExternalEvent)>) -> BTreeMap<usize, Vec<ExternalEvent>> {
let mut res: BTreeMap<usize, Vec<ExternalEvent>> = BTreeMap::new();
for (l, e) in v {
if e.is_arrow_ev() {
res.entry(*l).and_modify(|v| {v.push(e.clone())}).or_insert(vec![e.clone()]);
}
}
res
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ExternalEvent {
Bind {
from: ResourceTy,
to: ResourceTy,
id: usize
},
Copy {
from: ResourceTy,
to: ResourceTy,
is_partial: bool,
id: usize
},
Move {
from: ResourceTy,
to: ResourceTy,
is_partial: bool,
id: usize
},
StaticBorrow {
from: ResourceTy,
to: ResourceTy,
is_partial: bool,
id: usize
},
MutableBorrow {
from: ResourceTy,
to: ResourceTy,
is_partial: bool,
id: usize
},
StaticDie {
from: ResourceTy,
to: ResourceTy,
id: usize
},
MutableDie {
from: ResourceTy,
to: ResourceTy,
id: usize
},
RefDie {
from: ResourceTy,
to: ResourceTy,
num_curr_borrowers: usize,
id: usize
},
PassByStaticReference {
from: ResourceTy,
to: ResourceTy, id: usize
},
PassByMutableReference {
from: ResourceTy,
to: ResourceTy, id: usize
},
GoOutOfScope {
ro: ResourceAccessPoint,
id: usize
},
OwnerDropAtReassign {
ro: ResourceAccessPoint,
id: usize
},
InitRefParam {
param: ResourceAccessPoint,
id: usize
},
Branch {
live_vars: HashSet<ResourceAccessPoint>, branches: Vec<ExtBranchData>,
branch_type: BranchType,
split_point: usize,
merge_point: usize,
id: usize
}
}
impl Hash for ExternalEvent {
fn hash<H: Hasher>(&self, state: &mut H) {
self.get_id().hash(state);
}
}
impl ExternalEvent {
pub fn is_arrow_ev(&self) -> bool {
match self {
&ExternalEvent::Copy {..} | &ExternalEvent::Move {..} |
&ExternalEvent::StaticBorrow {..} | &ExternalEvent::StaticDie {..} |
&ExternalEvent::MutableBorrow {..} | &ExternalEvent::MutableDie {..} => true,
_ => false
}
}
pub fn is_gos_ev(&self) -> Option<&ResourceAccessPoint> {
match self {
ExternalEvent::GoOutOfScope { ro, .. } => Some(ro),
_ => None
}
}
pub fn get_id(&self) -> usize {
match self {
&ExternalEvent::Copy {id, ..} | &ExternalEvent::Move {id, ..} |
&ExternalEvent::StaticBorrow {id, ..} | &ExternalEvent::StaticDie {id, ..} |
&ExternalEvent::MutableBorrow {id, ..} | &ExternalEvent::MutableDie {id,..} |
&ExternalEvent::Branch { id, .. } | &ExternalEvent::GoOutOfScope { id , ..} |
&ExternalEvent::OwnerDropAtReassign { id, .. } |
&ExternalEvent::RefDie { id, .. } | &ExternalEvent::Bind { id, .. } |
&ExternalEvent::PassByStaticReference { id, .. } | &ExternalEvent::PassByMutableReference {id, .. } |
&ExternalEvent::InitRefParam { id, .. }=> id
}
}
}
#[derive(Debug, Clone)]
pub struct BranchData {
pub t_data: TimelineColumnData,
pub e_data: Vec<(usize, Event)>,
pub width: usize,
pub states: Vec<(usize, usize, State)>
}
#[derive(Debug, Clone)]
pub enum Event {
Acquire {
from: ResourceTy,
is: ResourceTy,
id: usize
},
Duplicate {
to: ResourceTy,
is: ResourceTy,
id: usize
},
Copy {
from: ResourceTy,
is: ResourceTy,
id: usize
},
Move {
to: ResourceTy,
is: ResourceTy,
id: usize
},
Branch {
is: ResourceTy,
branch_history: Vec<BranchData>,
ty: BranchType,
split_point: usize,
merge_point: usize,
id: usize
},
MutableLend {
to: ResourceTy,
is: ResourceTy,
id: usize
},
MutableBorrow {
from: ResourceTy,
is: ResourceTy,
id: usize
},
MutableDie {
to: ResourceTy,
is: ResourceTy,
id: usize
},
MutableReacquire {
from: ResourceTy,
is: ResourceTy,
id: usize
},
StaticLend {
to: ResourceTy,
is: ResourceTy,
id: usize
},
StaticBorrow {
from: ResourceTy,
is: ResourceTy,
id: usize
},
StaticDie {
to: ResourceTy,
is: ResourceTy,
id: usize
},
StaticReacquire {
from: ResourceTy,
is: ResourceTy,
id: usize
},
RefDie {
from: ResourceTy,
is: ResourceTy,
num_curr_borrowers: usize,
id: usize
},
OwnerGoOutOfScope,
RefGoOutOfScope,
OwnerDropAtReassign,
InitRefParam {
param: ResourceAccessPoint,
id: usize
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LineState {
Full,
Gray
}
#[derive(Clone, Debug)]
pub enum State {
OutOfScope,
ResourceMoved {
move_to: ResourceTy,
move_at_line: usize
},
FullPrivilege {
s: LineState
},
PartialPrivilege {
s: LineState
},
RevokedPrivilege {
to: ResourceTy,
borrow_to: ResourceTy,
prev_state: Box<State>
},
Invalid,
}
impl std::fmt::Display for State {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result {
match self {
State::OutOfScope => write!(f, "OutOfScope"),
State::ResourceMoved { move_to: _, move_at_line: _ } => write!(f, "ResourceMoved"),
State::FullPrivilege { .. } => write!(f, "FullPrivilege"),
State::PartialPrivilege { .. } => write!(f, "PartialPrivilege"),
State::RevokedPrivilege { .. } => write!(f, "RevokedPrivilege"),
State::Invalid => write!(f, "Invalid"),
}
}
}
fn safe_message(
message_functor: fn(&String, &String) -> String,
my_name: &String,
some_target: &ResourceTy
) -> String {
let target_name = match some_target {
ResourceTy::Deref(r) => {
let mut temp = r.name().clone();
temp.insert(0, '*');
temp
}
_ => some_target.name()
};
message_functor(my_name, &target_name)
}
impl State {
pub fn print_message_with_name(&self, my_name: &String) -> String {
match self {
State::OutOfScope => {
hover_messages::state_out_of_scope(my_name)
}
State::ResourceMoved{ move_to , move_at_line: _ } => {
safe_message(hover_messages::state_resource_moved, my_name, move_to)
}
State::FullPrivilege {..}=> {
hover_messages::state_full_privilege(my_name)
}
State::PartialPrivilege { .. } => {
hover_messages::state_partial_privilege(my_name)
}
State::RevokedPrivilege { to: _, borrow_to , prev_state: _} => {
safe_message(hover_messages::state_resource_revoked, my_name, borrow_to)
}
State::Invalid => {
hover_messages::state_invalid(my_name)
}
}
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for State {
fn cmp(&self, other: &Self) -> Ordering {
use State::*;
fn rank(s: &State) -> u8 {
match s {
ResourceMoved { .. } | RevokedPrivilege { .. } => 0,
PartialPrivilege { .. } => 1,
FullPrivilege {..} => 2,
Invalid | OutOfScope => 3,
}
}
let self_rank = rank(self);
let other_rank = rank(other);
self_rank.cmp(&other_rank)
}
}
impl PartialEq for State {
fn eq(&self, other: &State) -> bool {
match (self, other) {
(State::OutOfScope, State::OutOfScope) => true,
(State::PartialPrivilege { s }, State::PartialPrivilege { s: s2 }) => s == s2,
(State::FullPrivilege { s }, State::FullPrivilege { s: s2 }) => s == s2,
(State::ResourceMoved { .. }, State::ResourceMoved { .. }) => true,
_ => false
}
}
}
impl Eq for State {}
pub fn branch_state_converter(s: &State) -> State {
match s {
State::FullPrivilege { .. } => State::FullPrivilege { s: LineState::Gray },
State::PartialPrivilege { .. } => State::PartialPrivilege { s: LineState::Gray },
_ => s.clone()
}
}
pub fn convert_back(s: &State) -> State {
match s {
State::FullPrivilege { .. } => State::FullPrivilege { s: LineState::Full },
State::PartialPrivilege { .. } => State::PartialPrivilege { s: LineState::Full },
_ => s.clone()
}
}
pub fn clean_states(states: &Vec<(usize, usize, State)>) -> Vec<(usize, usize, State)> {
let mut cleaned_states: Vec<(usize, usize, State)> = Vec::new();
let mut i = 0;
while i < states.len() {
let mut j = i + 1;
let mut ending_range = states[i].1;
while j < states.len() && states[j].2 == states[i].2 {
ending_range = states[j].1;
j += 1;
}
cleaned_states.push((states[i].0, ending_range, states[i].2.clone()));
i = j;
}
cleaned_states
}
impl Display for Event {
fn fmt(&self, f: &mut Formatter) -> Result {
match self {
Event::Acquire{ from , ..} => { write!(f, "Acquiring resource from {}", from.name()) },
Event::Duplicate{ to , ..} => { write!(f, "Duplicating resource to {}", to.name())},
Event::Copy{ from , ..} => { write!(f, "Copying resource from {}", from.name())},
Event::Move{ to , ..} => {write!(f, "Moving resource to {}", to.name())},
Event::MutableLend{ to , ..} => {write!(f, "Mutable lend to {}", to.name())},
Event::MutableBorrow{ from , ..} => { write!(f, "Fully borrows resource from {}", from.name())},
Event::MutableDie{ to , ..} => { write!(f, "Fully returns resource to {}", to.name())},
Event::MutableReacquire{ from, .. } => {write!(f, "Fully reacquires resource from {}", from.name())},
Event::StaticLend{ to , ..} => {write!(f, "Partially lends resource to {}", to.name())},
Event::StaticBorrow{ from , ..} => { write!(f, "Partially borrows resource from {}", from.name())},
Event::StaticDie{ to , ..} => { write!(f, "Partially returns resource to {}", to.name())},
Event::StaticReacquire{ from , ..} => { write!(f, "Partially acquires resource from {}", from.name()) },
Event::InitRefParam{ param: _ , ..} => { write!(f, "Function parameter is initialized") },
Event::OwnerGoOutOfScope => {
write!(f, "Goes out of Scope as an owner of resource" ) }
Event::RefGoOutOfScope => {
write!(f, "Goes out of Scope as a reference to resource")
},
Event::OwnerDropAtReassign => {
write!(f, "Previous resource is dropped at reassignment")
},
Event::RefDie { from, .. } => {
write!(f, "{} reference dies", from.name())
}
Event::Branch { is, .. } => {
write!(f, "{} branch occuring ", is.real_name())
}
}
}
}
impl Event {
pub fn get_id(&self) -> usize {
match self {
Event::Duplicate {id: x , ..} | Event::Move {id: x, ..} | Event::StaticLend {id : x, ..} |
Event::MutableLend {id: x, ..} | Event::MutableDie {id: x, ..} | Event::StaticDie {id: x, ..} |
Event::Acquire { id: x, .. } | Event::Copy { id: x, .. } | Event::MutableBorrow { id: x, .. } |
Event::StaticBorrow { id: x, .. } | Event::StaticReacquire { id: x, .. } | Event::MutableReacquire {id: x, ..}
| Event::Branch { id: x, .. } | Event::InitRefParam { id: x, .. } => {
*x
}
_ => 1000000000
}
}
pub fn extract_is(&self) -> &ResourceTy {
match self {
Event::Duplicate {is: x , ..} | Event::Move {is: x, ..} | Event::StaticLend {is : x, ..} |
Event::MutableLend {is: x, ..} | Event::MutableDie {is: x, ..} | Event::StaticDie {is: x, ..} |
Event::Acquire { is: x, .. } | Event::Copy { is: x, .. } | Event::MutableBorrow { is: x, .. } |
Event::StaticBorrow { is: x, .. } | Event::StaticReacquire { is: x, .. } | Event::MutableReacquire {is: x, ..}
| Event::Branch { is: x, .. } => {
x
}
_ => &ResourceTy::Anonymous
}
}
pub fn is_branch(&self) -> bool {
match self {
Event::Branch { .. } => true,
_ => false
}
}
pub fn deref_name <'a>(&self, name: &'a mut String) -> & 'a String {
match self {
Event::Duplicate {is: x , ..} | Event::Move {is: x, ..} | Event::StaticLend {is : x, ..} |
Event::MutableLend {is: x, ..} | Event::MutableDie {is: x, ..} | Event::StaticDie {is: x, ..} |
Event::Acquire { is: x, .. } | Event::Copy { is: x, .. } | Event::MutableBorrow { is: x, .. } |
Event::StaticBorrow { is: x, .. } | Event::StaticReacquire { is: x, .. } | Event::MutableReacquire {is: x, ..} => {
match x {
ResourceTy::Deref(_) => {
name.insert(0, '*');
name
},
_ => name
}
},
_ => name
}
}
pub fn print_message_with_name(&self, my_name: &mut String) -> String {
match self {
Event::OwnerGoOutOfScope => {
hover_messages::event_dot_owner_go_out_out_scope(my_name)
}
Event::RefGoOutOfScope => {
hover_messages::event_dot_ref_go_out_out_scope(my_name)
}
Event::OwnerDropAtReassign => {
hover_messages::event_dot_owner_drop_at_reassign(my_name)
}
Event::InitRefParam{ param, .. } => {
match param {
ResourceAccessPoint::Owner(_) | ResourceAccessPoint::Struct(_) => {
hover_messages::event_dot_owner_init_from_caller(my_name)
}
ResourceAccessPoint::MutRef(_) => {
hover_messages::event_dot_ref_init_from_caller(my_name, true)
}
ResourceAccessPoint::StaticRef(_) => {
hover_messages::event_dot_ref_init_from_caller(my_name, false)
}
_ => hover_messages::event_dot_init_param(my_name),
}
}
Event::Duplicate{ to ,..} => {
match to {
ResourceTy::Caller => safe_message(hover_messages::event_dot_copy_to_caller, &self.deref_name(my_name), to),
_ => safe_message(hover_messages::event_dot_copy_to, &self.deref_name(my_name), to)
}
}
Event::Move{ to ,..} => {
match to {
ResourceTy::Caller => safe_message(hover_messages::event_dot_move_to_caller, &self.deref_name(my_name), to),
_ => safe_message(hover_messages::event_dot_move_to, &self.deref_name(my_name), to),
}
}
Event::StaticLend{ to ,..} => {
safe_message(hover_messages::event_dot_static_lend, &self.deref_name(my_name), to)
}
Event::MutableLend{ to ,..} => {
safe_message(hover_messages::event_dot_mut_lend, &self.deref_name(my_name), to)
}
Event::StaticDie{ to,.. } => {
safe_message(hover_messages::event_dot_static_return, &self.deref_name(my_name), to)
}
Event::MutableDie{ to ,..} => {
safe_message(hover_messages::event_dot_mut_return, &self.deref_name(my_name), to)
}
Event::Acquire{ from ,..} => {
safe_message(hover_messages::event_dot_acquire, &self.deref_name(my_name), from)
}
Event::Copy{ from ,..} => {
safe_message(hover_messages::event_dot_copy_from, &self.deref_name(my_name), from)
}
Event::MutableBorrow{ from ,..} => {
hover_messages::event_dot_mut_borrow(&self.deref_name(my_name), &from.name())
}
Event::StaticBorrow{ from ,..} => {
hover_messages::event_dot_static_borrow(&self.deref_name(my_name), &from.name())
}
Event::StaticReacquire{ from ,..} => {
safe_message(hover_messages::event_dot_static_reacquire, &self.deref_name(my_name), from)
}
Event::MutableReacquire{ from ,..} => {
safe_message(hover_messages::event_dot_mut_reacquire, &self.deref_name(my_name), from)
}
Event::RefDie {..} => {
panic!("should never be calling this function with this event");
},
Event::Branch { .. } => {
format!("{} is live in a conditional expression ", my_name)
}
}
}
}
#[derive(Debug, Clone)]
pub struct Timeline {
pub resource_access_point: ResourceAccessPoint,
pub history: Vec<(usize, Event)>,
pub states: Vec<(usize, usize, State)>
}
#[derive(Debug)]
pub struct StructsInfo {
pub structs: Vec<(i64, i64, i64)>,
}
#[derive(Debug)]
pub struct VisualizationData {
pub timelines: BTreeMap<u64, Timeline>,
pub external_events: Vec<(usize, ExternalEvent)>,
pub preprocess_external_events: Vec<(usize, ExternalEvent)>,
pub event_line_map: BTreeMap<usize, Vec<ExternalEvent>>,
pub num_valid_raps: usize,
pub fn_start_lines: HashMap<u64, usize>,
}
#[allow(non_snake_case)]
pub fn ResourceAccessPoint_extract (external_event : &ExternalEvent) -> (&ResourceTy, &ResourceTy){
let (from, to) = match external_event {
ExternalEvent::Bind{from: from_ro, to: to_ro, ..} => (from_ro, to_ro),
ExternalEvent::Copy{from: from_ro, to: to_ro, ..} => (from_ro, to_ro),
ExternalEvent::Move{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::StaticBorrow{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::StaticDie{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::MutableBorrow{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::MutableDie{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::PassByMutableReference{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
ExternalEvent::PassByStaticReference{from: from_ro, to: to_ro, .. } => (from_ro, to_ro),
_ => (&ResourceTy::Anonymous, &ResourceTy::Anonymous)
};
(from, to)
}
pub fn string_of_external_event(e: &ExternalEvent) -> String {
match e {
ExternalEvent::Bind{ .. } => {
String::from("Bind")
},
ExternalEvent::Copy{ is_partial,.. } => {
if *is_partial { String::from("Partial copy") }
else { String::from("Copy") }
},
ExternalEvent::Move{ is_partial, .. } => {
if *is_partial { String::from("Partial move")}
else { String::from("Move") }
},
ExternalEvent::StaticBorrow{ is_partial, .. } => {
if *is_partial { String::from("Partial immutable borrow") }
else { String::from("Immutable borrow") }
},
ExternalEvent::StaticDie{ .. } => {
String::from("Return immutably borrowed resource")
},
ExternalEvent::MutableBorrow{ is_partial, .. } => {
if *is_partial { String::from("Partial Mutable borrow") }
else { String::from("Mutable borrow")}
},
ExternalEvent::MutableDie{ .. } => {
String::from("Return mutably borrowed resource")
},
ExternalEvent::PassByMutableReference{ .. } => {
String::from("Pass by mutable reference")
},
ExternalEvent::PassByStaticReference{ .. } => {
String::from("Pass by immutable reference")
},
_ => unreachable!(),
}
}
impl Visualizable for VisualizationData {
fn get_name_from_hash(&self, hash: &u64) -> Option<String> {
match self.timelines.get(hash) {
Some(timeline) => Some(timeline.resource_access_point.name().to_owned()),
_ => None
}
}
fn is_mut(&self, hash: &u64) -> bool {
self.timelines[hash].resource_access_point.is_mut()
}
fn is_mutref(&self, hash: &u64) -> bool {
self.timelines[hash].resource_access_point.is_mutref()
}
fn is_ref(&self, hash: &u64) -> bool {
self.timelines[hash].resource_access_point.is_ref()
}
fn calc_state(&self, previous_state: & State, event: & Event, event_line: usize, hash: &u64) -> State {
fn event_invalid(event: & Event) -> bool {
match event {
Event::StaticBorrow{ from: ResourceTy::Value(ResourceAccessPoint::Function(_)) ,..} => true,
Event::MutableBorrow{ from: ResourceTy::Value(ResourceAccessPoint::Function(_)) ,..} => true,
Event::StaticDie{ to: ResourceTy::Value(ResourceAccessPoint::Function(_)) ,..} => true,
Event::MutableDie{ to: ResourceTy::Value(ResourceAccessPoint::Function(_)) ,..} => true,
_ => false,
}
}
if event_invalid(event) { return State::Invalid; }
match (previous_state, event) {
(State::Invalid, _) => State::Invalid,
(State::OutOfScope, Event::Acquire{ .. }) => State::FullPrivilege {s: LineState::Full},
(State::OutOfScope, Event::Copy{ from: ro, is: is_ro, ..}) => {
match ro {
ResourceTy::Anonymous => State::FullPrivilege {s: LineState::Full},
ResourceTy::Deref(r) | ResourceTy::Value(r) => {
if r.is_ref() && is_ro.is_ref() {
if r.is_mutref() {
panic!("Not possible, has to be a move");
}
else {
State::PartialPrivilege { s: LineState::Full }
}
}
else {
State::FullPrivilege {s: LineState::Full}
}
}
_ => panic!("not possible")
}
}
(State::OutOfScope, Event::StaticBorrow{ from: _ro,.. }) =>
State::PartialPrivilege {
s: LineState::Full
},
(State::OutOfScope, Event::MutableBorrow{ .. }) => State::FullPrivilege{s: LineState::Full},
(State::OutOfScope, Event::InitRefParam{ param: ro, .. }) => {
match ro {
ResourceAccessPoint::Function(..) => {
panic!("Cannot initialize function as as valid parameter!")
},
ResourceAccessPoint::Owner(..) | ResourceAccessPoint::MutRef(..) => {
State::FullPrivilege{s:LineState::Full}
},
ResourceAccessPoint::Struct(..) => {
State::FullPrivilege { s: LineState::Full }
},
ResourceAccessPoint::StaticRef(..) => {
State::PartialPrivilege { s: LineState::Full }
}
}
},
(State::FullPrivilege{..}, Event::Move{to: to_ro,..}) =>
State::ResourceMoved{ move_to: to_ro.to_owned(), move_at_line: event_line },
(State::ResourceMoved{ .. }, Event::Acquire{ .. }) => {
if self.is_mut(hash) {
State::FullPrivilege{ s: LineState::Full }
}
else { panic!("Immutable variable {} cannot reacquire resources!", self.get_name_from_hash(hash).unwrap());
}
},
(State::FullPrivilege{..}, Event::MutableLend{ to: to_ro ,..}) => {
if self.is_mut(hash) | self.is_mutref(hash) {
State::RevokedPrivilege{ to: ResourceTy::Anonymous, borrow_to: to_ro.to_owned(), prev_state: Box::from(previous_state.to_owned()) }
} else {
State::Invalid
}
},
(State::FullPrivilege{..}, Event::MutableDie{ .. }) =>
State::OutOfScope,
(State::FullPrivilege{..}, Event::Acquire{ from: _ ,..}) | (State::FullPrivilege{..}, Event::Copy{ from: _ ,..}) => {
State::FullPrivilege{ s: LineState::Full }
},
(State::FullPrivilege{..}, Event::OwnerGoOutOfScope) =>
State::OutOfScope,
(State::FullPrivilege{..}, Event::RefGoOutOfScope) =>
State::OutOfScope,
(State::FullPrivilege{..}, Event::StaticLend{ ..}) =>
State::PartialPrivilege { s: LineState::Full },
(State::PartialPrivilege{ .. }, Event::MutableLend{ to: to_ro, .. }) =>
State::RevokedPrivilege { to: ResourceTy::Anonymous, borrow_to: to_ro.to_owned(), prev_state: Box::from(previous_state.to_owned()) },
(State::PartialPrivilege{ .. }, Event::StaticLend{ ..}) => {
State::PartialPrivilege { s: LineState::Full }
}
(State::PartialPrivilege{ .. }, Event::StaticDie{ .. }) =>
State::OutOfScope,
(State::PartialPrivilege{ .. }, Event::StaticReacquire{ is, ..}) => {
if is.is_ref() && !is.is_mutref() { State::PartialPrivilege { s: LineState::Full }
}
else {
State::FullPrivilege {s: LineState::Full}
}
}
(State::PartialPrivilege { .. }, Event::RefDie { .. })=> {
State::PartialPrivilege{s: LineState::Full}
}
(State::PartialPrivilege{ .. }, Event::OwnerGoOutOfScope) =>
State::OutOfScope,
(State::PartialPrivilege{ .. }, Event::RefGoOutOfScope) =>
State::OutOfScope,
(State::RevokedPrivilege{ prev_state: p,.. }, Event::MutableReacquire{ .. }) => {
*p.clone()
}
(State::FullPrivilege{..}, Event::StaticDie { .. }) |
(State::FullPrivilege{..}, Event::StaticBorrow { .. }) => {
State::FullPrivilege{s: LineState::Full}
}
(State::FullPrivilege{..}, Event::StaticReacquire { .. }) => {
State::FullPrivilege { s: LineState::Full }
}
(State::FullPrivilege{..}, Event::MutableReacquire { .. }) => {
State::FullPrivilege { s: LineState::Full }
}
(_, Event::Duplicate { to: ResourceTy::Caller,..}) => State::OutOfScope,
(_, Event::Duplicate { .. }) => (*previous_state).clone(),
(_, Event::Branch { .. }) => { State::OutOfScope
}
(_, Event::OwnerGoOutOfScope) | (_, Event::RefGoOutOfScope) => State::OutOfScope,
(_, Event::OwnerDropAtReassign) => (*previous_state).clone(),
(_, _) => State::Invalid,
}
}
fn compute_branch_states(&self,
history: & mut Vec<(usize, Event)>,
states: & mut Vec<(usize, usize, State)>,
hash: &u64,
valid_range: (usize, usize),
branch_start: usize,
branch_end: usize,
mut previous_state: State) -> State{
if history.is_empty() {
states.push((branch_start, branch_end, branch_state_converter(&previous_state)));
return previous_state;
}
let (begin, end) = valid_range;
if begin != branch_start {
states.push((branch_start, begin, branch_state_converter(&previous_state)));
}
let mut previous_line = begin;
for (l, e) in history {
states.push((previous_line, *l, previous_state.clone()));
match e {
Event::Branch { branch_history, ty, split_point, merge_point, .. } => {
states.push((*split_point, *merge_point, State::OutOfScope));
let mut ending_states: Vec<State> = Vec::new();
for (i, branch) in branch_history.iter_mut().enumerate() {
ending_states.push(self.compute_branch_states(
& mut branch.e_data,
& mut branch.states,
hash,
ty.get_start_end(i),
*split_point + 1,
*merge_point,
previous_state.clone()));
}
ending_states.sort(); previous_state = convert_back(&ending_states.first().unwrap());
previous_line = *merge_point + 1; }
_ => {
previous_state = self.calc_state(&previous_state, e, *l, hash);
previous_line = *l;
}
}
}
states.push((previous_line, end, previous_state.clone()));
if end != branch_end {
states.push((end, branch_end, branch_state_converter(&previous_state)));
}
*states = clean_states(&states);
states.last().unwrap().2.clone() }
fn compute_timeline_states(&self, history: & mut Vec<(usize, Event)>, states: & mut Vec<(usize, usize, State)>, hash: &u64) {
let mut previous_line = 1;
let mut previous_state = State::OutOfScope;
for (l, e) in history {
states.push((previous_line, *l, previous_state.clone()));
match e {
Event::Branch { branch_history, ty, split_point, merge_point, .. } => {
states.push((*split_point, *merge_point, State::OutOfScope));
let mut ending_states: Vec<State> = Vec::new();
for (i, branch) in branch_history.iter_mut().enumerate() {
ending_states.push(self.compute_branch_states(
& mut branch.e_data,
& mut branch.states,
hash,
ty.get_start_end(i),
*split_point + 1,
*merge_point,
previous_state.clone()));
}
ending_states.sort(); previous_state = convert_back(&ending_states.first().unwrap());
previous_line = *merge_point + 1;
}
_ => {
previous_state = self.calc_state(&previous_state, e, *l, hash);
previous_line = *l;
}
}
}
states.push((previous_line, previous_line, previous_state));
*states = clean_states(&states);
}
fn compute_states(&mut self) {
let mut timelines = self.timelines.clone(); for (hash, timeline) in timelines.iter_mut() {
self.compute_timeline_states(& mut timeline.history, &mut timeline.states, hash);
}
self.timelines = timelines;
}
fn _append_event(&mut self, resource_access_point: &ResourceAccessPoint, event: Event, line_number: &usize) {
let hash = &resource_access_point.hash();
match self.timelines.get(hash) {
None => {
let timeline = Timeline {
resource_access_point: resource_access_point.clone(),
history: Vec::new(),
states: Vec::new()
};
self.timelines.insert(**hash, timeline);
},
_ => {}
}
match self.timelines.get_mut(hash) {
Some(timeline) => {
timeline.history.push(
(*line_number, event)
);
},
_ => {
panic!("Timeline disappeared right after creation or when we could index it. This is impossible.");
}
}
}
fn event_of_exteranl_event(&self, line_num: usize, ext_ev: &ExternalEvent, to_o: bool) -> Vec<(usize, Event)> {
match ext_ev {
ExternalEvent::Bind { from, to, id } => {
if to_o { vec![(line_num, Event::Acquire{from : from.to_owned(), is: to.clone(), id: *id})] }
else { vec![(line_num, Event::Duplicate{to : to.to_owned(), is: from.clone(), id: *id})] }
},
ExternalEvent::Copy{from: from_ro, to: to_ro, id, ..} => {
if to_o { vec![(line_num, Event::Copy{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})] }
else { vec![(line_num, Event::Duplicate{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::Move{from: from_ro, to: to_ro, id, ..} => {
if to_o { vec![(line_num, Event::Acquire{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})] }
else { vec![(line_num, Event::Move{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::StaticBorrow{from: from_ro, to: to_ro, id, ..} => {
if to_o { vec![(line_num, Event::StaticBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})] }
else { vec![(line_num, Event::StaticLend{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::StaticDie{from: from_ro, to: to_ro, id} => {
if to_o && !from_ro.is_same_underlying(&to_ro){
vec![(line_num, Event::StaticReacquire{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})]
}
else { vec![(line_num, Event::StaticDie{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::MutableBorrow{from: from_ro, to: to_ro, id, ..} => {
if to_o { vec![(line_num, Event::MutableBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})] }
else { vec![(line_num, Event::MutableLend{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::MutableDie{from: from_ro, to: to_ro, id} => {
if to_o && !from_ro.is_same_underlying(&to_ro){
vec![(line_num, Event::MutableReacquire{from : from_ro.to_owned(), is: to_ro.clone(), id: *id})]
}
else { vec![(line_num, Event::MutableDie{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
},
ExternalEvent::RefDie { from: from_ro, to: to_ro, id ,..} => {
match from_ro.clone() {
ResourceTy::Deref(ro_is) | ResourceTy::Value(ro_is) => {
if ro_is.is_mutref() && !to_o {
vec![(line_num, Event::MutableDie {to: ResourceTy::Anonymous, is: from_ro.clone(), id: *id})]
}
else {
if to_o { vec![] }
else { vec![(line_num, Event::StaticDie{to : to_ro.to_owned(), is: from_ro.clone(), id: *id})] }
}
}
_ => panic!("not possible")
}
},
ExternalEvent::PassByStaticReference{from: from_ro, to: to_ro, id} => {
if to_o {
vec![(line_num, Event::StaticBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: *id}),
(line_num, Event::StaticDie{to : from_ro.to_owned(), is: to_ro.clone(), id: *id})]
}
else {
vec![(line_num, Event::StaticLend{to : to_ro.to_owned(), is: from_ro.clone(), id: *id}),
(line_num, Event::StaticReacquire{from : to_ro.to_owned(), is: from_ro.clone(), id: *id})]
}
},
ExternalEvent::PassByMutableReference{from: from_ro, to: to_ro, id} => {
if to_o {
vec![(line_num, Event::MutableBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: *id}),
(line_num, Event::MutableDie{to : from_ro.to_owned(), is: to_ro.clone(), id: *id})]
}
else {
vec![(line_num, Event::MutableLend{to : to_ro.to_owned(), is: from_ro.clone(), id: *id}),
(line_num, Event::MutableReacquire{from : to_ro.to_owned(), is: from_ro.clone(), id: *id})]
}
},
ExternalEvent::InitRefParam{param: ro, id} => {
vec![(line_num, Event::InitRefParam{param : ro.to_owned(), id: *id})]
},
ExternalEvent::GoOutOfScope{ro,..} => {
match ro {
ResourceAccessPoint::Owner(..) | ResourceAccessPoint::Struct(..) => {
vec![(line_num, Event::OwnerGoOutOfScope)]
},
ResourceAccessPoint::MutRef(..) | ResourceAccessPoint::StaticRef(..)=> {
vec![(line_num, Event::RefGoOutOfScope)]
},
ResourceAccessPoint::Function(func) => {
panic!(
"Functions do not go out of scope! We do not expect to see \"{}\" here.",
func.name
);
}
}
},
ExternalEvent::OwnerDropAtReassign{..} => {
vec![(line_num, Event::OwnerDropAtReassign)]
},
_ => panic!("should not be calling this on branches")
}
}
fn append_branch_event(&self, event: &ExternalEvent, line_number: usize, is: &ResourceTy, b_history: &mut Vec<(usize, Event)>) {
let rap = is.extract_rap().unwrap();
match event {
ExternalEvent::Branch { live_vars, branches, branch_type, split_point, merge_point, id } => {
if live_vars.contains(rap) {
let mut new_branches: Vec<BranchData> = Vec::new();
for b in branches.iter() {
let mut new_b_history: Vec<(usize, Event)> = Vec::new();
for (l, e) in b.e_data.iter() {
self.append_branch_event(e, *l, is, & mut new_b_history);
}
new_branches.push(BranchData { t_data: TimelineColumnData { name: "".to_owned(),
x_val: -1,
title: "".to_owned(),
is_ref: false,
is_struct_group: false,
is_member: false,
owner: 0
}, e_data: new_b_history, width: 0, states: Vec::new() });
}
b_history.push((line_number,
Event::Branch { is: is.clone(),
branch_history: new_branches,
ty: branch_type.clone(),
split_point: *split_point,
merge_point: *merge_point,
id: *id}));
}
}
_ => {
let could_be = ResourceTy::Deref(rap.clone());
let (from, to) = ResourceAccessPoint_extract(event);
if *from == *is || *from == could_be {
b_history.extend(self.event_of_exteranl_event(line_number, event, false));
}
else if *to == *is || *to == could_be {
b_history.extend(self.event_of_exteranl_event(line_number, event, true));
}
else if let Some(r) = event.is_gos_ev() {
if *r.name() == is.real_name() {
b_history.extend(self.event_of_exteranl_event(line_number, event, true));
}
}
}
}
}
fn append_decl_branch_events(&mut self, b_history: &Vec<(usize, ExternalEvent)>) {
for (_l, e) in b_history {
match e {
ExternalEvent::Branch { branches, .. } => {
for branch in branches.iter() {
for var in branch.decl_vars.iter() {
let mut b_history: Vec<(usize, Event)> = Vec::new();
let is = &ResourceTy::Value(var.clone());
for (l, e) in branch.e_data.iter() {
self.append_branch_event(e, *l, is, & mut b_history);
}
for (l, e) in b_history {
self._append_event(var, e, &l);
}
}
self.append_decl_branch_events(&branch.e_data);
}
}
_ => {}
}
}
}
fn append_processed_external_event(&mut self, event: ExternalEvent, line_number: usize) {
self.external_events.push((line_number, event.clone()));
fn maybe_append_event (vd: & mut VisualizationData, resource_ty: &ResourceTy, event: Event, line_number: usize){
match resource_ty {
ResourceTy::Anonymous | ResourceTy::Caller => {}
ResourceTy::Deref(r) | ResourceTy::Value(r) => {
vd._append_event(&r, event, &line_number);
}
}
}
match event {
ExternalEvent::Move{from: from_ro, to: to_ro, id, ..} => {
maybe_append_event(self, &to_ro.clone(), Event::Acquire{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
maybe_append_event(self, &from_ro.clone(), Event::Move{to : to_ro.to_owned(), is: from_ro, id: id}, line_number);
},
ExternalEvent::Bind{from: from_ro, to: to_ro, id} => {
maybe_append_event(self, &to_ro.clone(), Event::Acquire{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
maybe_append_event(self, &from_ro.clone(), Event::Duplicate{to : to_ro.to_owned(), is: from_ro, id: id}, line_number);
},
ExternalEvent::Copy{from: from_ro, to: to_ro, id, ..} => {
maybe_append_event(self, &to_ro.clone(), Event::Copy{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
maybe_append_event(self, &from_ro.clone(), Event::Duplicate{to : to_ro.to_owned(), is: from_ro, id: id}, line_number);
},
ExternalEvent::Branch { live_vars, branches, branch_type, split_point, merge_point, id } => {
for var in live_vars.iter() { let is = ResourceTy::Value(var.clone());
let mut branch_history: Vec<BranchData> = Vec::new();
for branch in branches.iter() { let mut b_history: Vec<(usize, Event)> = Vec::new();
for (l, ev) in branch.e_data.iter() { self.append_branch_event(ev, *l, &is, & mut b_history);
}
branch_history.push(BranchData { t_data: TimelineColumnData { name: "".to_owned(),
x_val: -1,
title: "".to_owned(),
is_ref: false,
is_struct_group: false,
is_member: false,
owner: 0
}, e_data: b_history, width: 0, states: Vec::new() });
}
maybe_append_event(self, &is.clone(), Event::Branch {
is: is,
branch_history: branch_history,
ty: branch_type.clone(),
split_point: split_point,
merge_point: merge_point,
id: id}, line_number);
}
for branch in branches.iter() {
for var in branch.decl_vars.iter() {
let mut b_history: Vec<(usize, Event)> = Vec::new();
let is = &ResourceTy::Value(var.clone());
for (l, e) in branch.e_data.iter() {
self.append_branch_event(e, *l, is, & mut b_history);
}
for (l, e) in b_history {
self._append_event(var, e, &l);
}
}
self.append_decl_branch_events(&branch.e_data);
}
}
ExternalEvent::StaticBorrow{from: from_ro, to: to_ro, id, ..} => {
maybe_append_event(self, &from_ro, Event::StaticLend{to : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.clone(), Event::StaticBorrow{from : from_ro.to_owned(), is: to_ro, id: id}, line_number);
},
ExternalEvent::StaticDie{from: from_ro, to: to_ro, id} => {
if !from_ro.is_same_underlying(&to_ro) {
maybe_append_event(self, &to_ro.clone(), Event::StaticReacquire{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
}
maybe_append_event(self, &from_ro.clone(), Event::StaticDie{to : to_ro.to_owned(), is: from_ro, id: id}, line_number);
},
ExternalEvent::MutableBorrow{from: from_ro, to: to_ro, id, ..} => {
maybe_append_event(self, &from_ro, Event::MutableLend{to : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.clone(), Event::MutableBorrow{from : from_ro.to_owned(), is: to_ro, id: id}, line_number);
},
ExternalEvent::MutableDie{from: from_ro, to: to_ro, id} => {
if !from_ro.is_same_underlying(&to_ro) {
maybe_append_event(self, &to_ro.clone(), Event::MutableReacquire{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
}
maybe_append_event(self, &from_ro.clone(), Event::MutableDie{to : to_ro.to_owned(), is: from_ro, id: id}, line_number);
},
ExternalEvent::RefDie { from: from_ro, to: _, id, ..} => { match from_ro.clone() {
ResourceTy::Deref(ro_is) | ResourceTy::Value(ro_is) => {
if ro_is.is_mutref() {
maybe_append_event(self, &from_ro.clone(), Event::MutableDie { to: ResourceTy::Anonymous, is: from_ro.clone(), id: id }, line_number);
}
else {
maybe_append_event(self, &from_ro.clone(), Event::StaticDie { to: ResourceTy::Anonymous, is: from_ro.clone(), id: id }, line_number);
}
}
_ => panic!("not possible")
}
},
ExternalEvent::PassByStaticReference{from: from_ro, to: to_ro, id} => {
maybe_append_event(self, &from_ro.to_owned(), Event::StaticLend{to : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.to_owned(), Event::StaticBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
maybe_append_event(self, &from_ro, Event::StaticReacquire{from : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.clone(), Event::StaticDie{to : from_ro.to_owned(), is: to_ro, id: id}, line_number);
},
ExternalEvent::PassByMutableReference{from: from_ro, to: to_ro, id} => {
maybe_append_event(self, &from_ro.clone(), Event::MutableLend{to : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.clone(), Event::MutableBorrow{from : from_ro.to_owned(), is: to_ro.clone(), id: id}, line_number);
maybe_append_event(self, &from_ro.clone(), Event::MutableReacquire{from : to_ro.to_owned(), is: from_ro.clone(), id: id}, line_number);
maybe_append_event(self, &to_ro.clone(), Event::MutableDie{to : from_ro.to_owned(), is: to_ro, id: id}, line_number);
},
ExternalEvent::InitRefParam{param: ro, id} => {
maybe_append_event(self, &ResourceTy::Value(ro.clone()), Event::InitRefParam{param : ro.to_owned(), id: id}, line_number);
},
ExternalEvent::GoOutOfScope{ro, ..} => {
match ro {
ResourceAccessPoint::Owner(..) | ResourceAccessPoint::Struct(..) => {
maybe_append_event(self, &ResourceTy::Value(ro), Event::OwnerGoOutOfScope, line_number);
},
ResourceAccessPoint::MutRef(..) | ResourceAccessPoint::StaticRef(..)=> {
maybe_append_event(self, &ResourceTy::Value(ro), Event::RefGoOutOfScope, line_number);
},
ResourceAccessPoint::Function(func) => {
panic!(
"Functions do not go out of scope! We do not expect to see \"{}\" here.",
func.name
);
}
}
},
ExternalEvent::OwnerDropAtReassign{ro, ..} => {
maybe_append_event(self, &ResourceTy::Value(ro), Event::OwnerDropAtReassign, line_number);
},
}
}
}