rustviz_lib/
data.rs

1use std::collections::{HashSet, BTreeMap};
2use std::vec::Vec;
3use std::fmt::{Formatter, Result, Display};
4use crate::data::Event::*;
5use crate::hover_messages;
6/*
7 * Basic Data Structure Needed by Lifetime Visualization
8 */
9pub static LINE_SPACE: i64 = 30;
10// Top level Api that the Timeline object supports
11pub trait Visualizable {
12    // returns None if the hash does not exist
13    fn get_name_from_hash(&self, hash: &u64) -> Option<String>;
14    
15    // returns None if the hash does not exist
16    fn get_state(&self, hash: &u64, line_number: &usize) -> Option<State>;
17    
18    // for querying states of a resource owner using its hash
19    //                                         start line, end line, state
20    fn get_states(&self, hash: &u64) -> Vec::<(usize,      usize,    State)>;
21
22    // WARNING do not call this when making visualization!! 
23    // use append_external_event instead
24    fn _append_event(&mut self, resource_access_point: &ResourceAccessPoint, event: Event, line_number: &usize);
25    
26    // add an event to the Visualizable data structure
27    fn append_processed_external_event(&mut self, event: ExternalEvent, line_number: usize);
28    
29    // preprocess externa event information for arrow overlapping issue
30    fn append_external_event(&mut self, event: ExternalEvent, line_number: &usize);
31    // if resource_access_point with hash is mutable
32    fn is_mut(&self, hash: &u64 ) -> bool;
33    // if resource_access_point with hash is a function
34    fn is_mutref(&self, hash: &u64) -> bool;
35
36    fn calc_state(&self, previous_state: & State, event: & Event, event_line: usize, hash: &u64) -> State;
37}
38
39
40// Every object in Rust should belong in one of these catagories
41// A ResourceAccessPoint is either an Owner, a reference, or a Function that
42// have ownership to a memory object, during some stage of
43// a the program execution.
44#[derive(Clone, Hash, PartialEq, Eq, Debug)]
45pub enum ResourceAccessPoint {
46    Owner(Owner),
47    MutRef(MutRef),
48    StaticRef(StaticRef),
49    Function(Function),
50    Struct(Struct),
51}
52
53// when something is not a reference
54#[derive(Clone, Hash, PartialEq, Eq, Debug)]
55pub struct Owner {
56    pub name: String,
57    pub hash: u64,
58    pub is_mut: bool,                     // let a = 42; vs let mut a = 42;
59}
60
61// when something is a struct member
62#[derive(Clone, Hash, PartialEq, Eq, Debug)]
63pub struct Struct {
64    pub name: String,
65    pub hash: u64,
66    pub owner: u64,
67    pub is_mut: bool,                     
68    pub is_member: bool
69}
70
71// a reference of type &mut T
72#[derive(Clone, Hash, PartialEq, Eq, Debug)]
73pub struct MutRef {         // let (mut) r1 = &mut a;
74    pub name: String,
75    pub hash: u64,
76    pub is_mut: bool,
77}
78
79// a reference of type & T
80#[derive(Clone, Hash, PartialEq, Eq, Debug)]
81pub struct StaticRef {                // let (mut) r1 = & a;
82    pub name: String,
83    pub hash: u64,
84    pub is_mut: bool,
85}
86
87#[derive(Clone, Hash, PartialEq, Eq, Debug)]
88pub struct Function {
89    pub name: String,
90    pub hash: u64,
91}
92
93
94impl ResourceAccessPoint {
95    // get the attribute hash
96    pub fn hash(&self) -> &u64 {
97        match self {
98            ResourceAccessPoint::Owner(Owner{hash, ..}) => hash,
99            ResourceAccessPoint::Struct(Struct{hash, ..}) => hash,
100            ResourceAccessPoint::MutRef(MutRef{hash, ..}) => hash,
101            ResourceAccessPoint::StaticRef(StaticRef{hash, ..}) => hash,
102            ResourceAccessPoint::Function(Function{hash, ..}) => hash,
103        }
104    }
105
106    // get the name field
107    pub fn name(&self) -> &String {
108        match self {
109            ResourceAccessPoint::Owner(Owner{name, ..}) => name,
110            ResourceAccessPoint::Struct(Struct{name, ..}) => name,
111            ResourceAccessPoint::MutRef(MutRef{name, ..}) => name,
112            ResourceAccessPoint::StaticRef(StaticRef{name, ..}) => name,
113            ResourceAccessPoint::Function(Function{name, ..}) => name,
114        }
115    }
116
117    // get the is_mut field, if any
118    pub fn is_mut(&self) -> bool {
119        match self {
120            ResourceAccessPoint::Owner(Owner{is_mut, ..}) => is_mut.to_owned(),
121            ResourceAccessPoint::Struct(Struct{is_mut, ..}) => is_mut.to_owned(),
122            ResourceAccessPoint::MutRef(MutRef{is_mut, ..}) => is_mut.to_owned(),
123            ResourceAccessPoint::StaticRef(StaticRef{is_mut, ..}) => is_mut.to_owned(),
124            ResourceAccessPoint::Function(_) => false,
125        }
126    }
127
128    pub fn is_ref(&self) -> bool {
129        match self {
130            ResourceAccessPoint::Owner(_) => false,
131            ResourceAccessPoint::Struct(_) => false,
132            ResourceAccessPoint::MutRef(_) => true,
133            ResourceAccessPoint::StaticRef(_) => true,
134            ResourceAccessPoint::Function(_) => false,
135        }
136    }
137
138    pub fn is_mutref(&self) -> bool {
139        match self {
140            ResourceAccessPoint::MutRef(_) => true,
141            _ => false
142        }
143    }
144
145    pub fn is_struct_group(&self) -> bool {
146        match self {
147            ResourceAccessPoint::Owner(_) => false,
148            ResourceAccessPoint::Struct(_) => true,
149            ResourceAccessPoint::MutRef(_) => false,
150            ResourceAccessPoint::StaticRef(_) => false,
151            ResourceAccessPoint::Function(_) => false,
152        }
153    }
154
155    pub fn is_struct(&self) -> bool {
156        match self {
157            ResourceAccessPoint::Owner(_) => false,
158            ResourceAccessPoint::Struct(Struct{is_member, ..}) => !is_member.to_owned(),
159            ResourceAccessPoint::MutRef(_) => false,
160            ResourceAccessPoint::StaticRef(_) => false,
161            ResourceAccessPoint::Function(_) => false,
162        }
163    }
164
165    pub fn is_member(&self) -> bool {
166        match self {
167            ResourceAccessPoint::Owner(_) => false,
168            ResourceAccessPoint::Struct(Struct{is_member, ..}) => is_member.to_owned(),
169            ResourceAccessPoint::MutRef(_) => false,
170            ResourceAccessPoint::StaticRef(_) => false,
171            ResourceAccessPoint::Function(_) => false,
172        }
173    }
174
175    pub fn get_owner(&self) -> u64 {
176        match self {
177            ResourceAccessPoint::Owner(Owner{hash, ..}) => hash.to_owned(),
178            ResourceAccessPoint::Struct(Struct{owner, ..}) => owner.to_owned(),
179            ResourceAccessPoint::MutRef(MutRef{hash, ..}) => hash.to_owned(),
180            ResourceAccessPoint::StaticRef(StaticRef{hash, ..}) => hash.to_owned(),
181            ResourceAccessPoint::Function(Function{hash, ..}) => hash.to_owned(),
182        }
183    }
184}
185
186#[derive(Clone, Hash, PartialEq, Eq, Debug)]
187pub enum ExternalEvent {
188    /* let binding, e.g.: let x = 1 */
189    Bind {
190        from: Option<ResourceAccessPoint>,
191        to: Option<ResourceAccessPoint>
192    },
193    Copy {
194        from: Option<ResourceAccessPoint>,
195        to: Option<ResourceAccessPoint>
196    },
197    Move {
198        from: Option<ResourceAccessPoint>,
199        to: Option<ResourceAccessPoint>,
200    },
201    StaticBorrow {
202        from: Option<ResourceAccessPoint>,
203        to: Option<ResourceAccessPoint>,
204    },
205    MutableBorrow {
206        from: Option<ResourceAccessPoint>,
207        to: Option<ResourceAccessPoint>,
208    },
209    StaticDie {
210        // return the resource to "to"
211        from: Option<ResourceAccessPoint>,
212        to: Option<ResourceAccessPoint>,
213    },
214    MutableDie {
215        // return the resource to "to"
216        from: Option<ResourceAccessPoint>,
217        to: Option<ResourceAccessPoint>,
218    },
219    // a use of the Owner, happens when var pass by reference
220    // its really borrow and return but happens on the same line,
221    // use this event instead of borrow and return for more concise visualization 
222    PassByStaticReference {
223        from: Option<ResourceAccessPoint>,
224        to: Option<ResourceAccessPoint>, // must be a function
225    },
226    PassByMutableReference {
227        from: Option<ResourceAccessPoint>,
228        to: Option<ResourceAccessPoint>, // must be a function
229    },
230    GoOutOfScope {
231        ro: ResourceAccessPoint
232    },
233    // only use this event to initialize fn parameters
234    InitRefParam {
235        param: ResourceAccessPoint,
236    },
237}
238
239
240// ASSUMPTION: a reference must return resource before borrow;
241//
242// An Event describes the acquisition or release of a
243// resource ownership by a Owner on any given line.
244// There are six types of them.
245#[derive(Debug)]
246pub enum Event {
247    // this happens when a variable is initiated, it should obtain
248    // its resource from either another variable or from a
249    // contructor.
250    //
251    // E.g. in the case of
252    //      let x = Vec::new();
253    // x obtained the resource from global resource allocator,
254    // the Acquire Event's "from" variable is None.
255    // in the case of
256    //      let y = x;
257    // y obtained its value from x, which means that the Acquire
258    // Event's "from" variable is x.
259    // TODO do we need mut/static_acquire for get_state?
260    Acquire {
261        from: Option<ResourceAccessPoint>
262    },
263    // this happens when a ResourceAccessPoint implements copy trait or
264    // explicitly calls .clone() function
265    // to another ResourceAccessPoint, or a function.
266    //
267    // e.g.
268    // 1. x: i32 = y + 15;              here y duplicate to + op, and x acquire from +
269    //                                  at this point, we treat it as y duplicates to None
270    // 2. x: MyStruct = y.clone();      here y duplicates to x.
271    Duplicate {
272        to: Option<ResourceAccessPoint>
273    },
274    // this happens when a ResourceAccessPoint transfers a copy of its contents
275    // to another ResourceAccessPoint.
276    // Typically, this occurs when a resource owner implements the Copy trait.
277    Copy {
278        from: Option<ResourceAccessPoint>
279    },
280    // this happens when a ResourceAccessPoint transfer the ownership of its resource
281    // to another ResourceAccessPoint, or if it is no longer used after this line.
282    // Typically, this happens at one of the following two cases:
283    //
284    // 1. variable is not used after this line.
285    // 2. variable's resource has the move trait, and it transfered
286    //    its ownership on this line. This includes tranfering its
287    //    ownership to a function as well.
288    Move {
289        to: Option<ResourceAccessPoint>
290    },
291    MutableLend {
292        to: Option<ResourceAccessPoint>
293    },
294    MutableBorrow {
295        from: ResourceAccessPoint
296    },
297    MutableDie {
298        to: Option<ResourceAccessPoint>
299    },
300    MutableReacquire {
301        from: Option<ResourceAccessPoint>
302    },
303    StaticLend {
304        to: Option<ResourceAccessPoint>
305    },
306    StaticBorrow {
307        from: ResourceAccessPoint
308    },
309    StaticDie {
310        to: Option<ResourceAccessPoint>
311    },
312    StaticReacquire {
313        from: Option<ResourceAccessPoint>
314    },
315    // this happens when a owner is returned this line,
316    // or if this owner's scope ends at this line. The data must be dropped. 
317    OwnerGoOutOfScope,
318    // this happens when a vairable that is not an owner goes out of scope. 
319    // The data is not dropped in this case
320    RefGoOutOfScope,
321    // SPECIAL CASE: use only to initialize a fn's paramter
322    // Requires param to be Owner, StaticRef, or MutRef (cannot be Function)
323    InitRefParam {
324        param: ResourceAccessPoint
325    },
326}
327
328// A State is a description of a ResourceAccessPoint IMMEDIATELY AFTER a specific line.
329// We think of this as what read/write access we have to its resource.
330#[derive(Clone)]
331pub enum State {
332    // The viable is no longer in the scope after this line.
333    OutOfScope,
334    // The resource is transferred on this line or before this line,
335    // thus it is impossible to access this variable anymore.
336    ResourceMoved {
337        move_to: Option<ResourceAccessPoint>,
338        move_at_line: usize
339    },
340    // This ResourceAccessPoint is the unique object that holds the ownership to the underlying resource.
341    FullPrivilege,
342    // More than one ResourceAccessPoint has access to the underlying resource
343    // This means that it is not possible to create a mutable reference
344    // on the next line.
345    // About borrow_count: this value is at least one at any time.
346    //      When the first static reference of this ResourceAccessPoint is created,
347    //          this value is set to 1;
348    //      When a new static reference is borrowed from this variable, increment by 1;
349    //      When a static reference goes out of scope, decrement this value by 1;
350    //      When a decrement happens while the borrow_count is 1, the state becomes
351    //          FullPrivilege once again.
352    PartialPrivilege {
353        borrow_count: u32,
354        borrow_to: HashSet<ResourceAccessPoint>
355    },
356    // temporarily no read or write access right to the resource, but eventually
357    // the privilege will come back. Occurs when mutably borrowed
358    RevokedPrivilege {
359        to: Option<ResourceAccessPoint>,
360        borrow_to: Option<ResourceAccessPoint>,
361    },
362    // should not appear for visualization in a correct program
363    Invalid,
364}
365
366impl std::fmt::Display for State {
367    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result {
368        match self {
369            State::OutOfScope => write!(f, "OutOfScope"),
370            State::ResourceMoved { move_to: _, move_at_line: _ } => write!(f, "ResourceMoved"),
371            State::FullPrivilege => write!(f, "FullPrivilege"),
372            State::PartialPrivilege { .. } => write!(f, "PartialPrivilege"),
373            State::RevokedPrivilege { .. } => write!(f, "RevokedPrivilege"),
374            State::Invalid => write!(f, "Invalid"),
375        }
376    }
377}
378
379
380fn safe_message(
381    message_functor: fn(&String, &String) -> String,
382    my_name: &String,
383    some_target: &Option<ResourceAccessPoint>
384) -> String {
385    if let Some(target) = some_target {
386        message_functor(my_name, target.name())
387    }
388    else {
389        message_functor(my_name, &"another value".to_owned())
390    }
391}
392
393
394impl State {
395    pub fn print_message_with_name(&self, my_name: &String) -> String {
396        match self {
397            State::OutOfScope => {
398                hover_messages::state_out_of_scope(my_name)
399            }
400            State::ResourceMoved{ move_to , move_at_line: _ } => {
401                safe_message(hover_messages::state_resource_moved, my_name, move_to)
402            }
403            State::FullPrivilege => {
404                hover_messages::state_full_privilege(my_name)
405            }
406            State::PartialPrivilege { .. } => {
407                hover_messages::state_partial_privilege(my_name)
408            }
409            State::RevokedPrivilege { to: _, borrow_to } => {
410                safe_message(hover_messages::state_resource_revoked, my_name, borrow_to)
411            }
412            State::Invalid => {
413                hover_messages::state_invalid(my_name)
414            }
415        }
416    }
417}
418
419// provide string output for usages like format!("{}", eventA)
420impl Display for Event {
421    fn fmt(&self, f: &mut Formatter) -> Result {       
422        let mut from_ro = None;
423        let mut to_ro = None;
424        let mut display = match self {
425            Event::Acquire{ from } => { from_ro = from.to_owned(); "" },
426            Event::Duplicate{ to } => { to_ro = to.to_owned(); "Copying resource" },
427            Event::Copy{ from } => { from_ro = from.to_owned(); "Copying resource from some variable" },
428            Event::Move{ to } => { to_ro = to.to_owned(); "Moving resource" },
429            Event::MutableLend{ to } => { to_ro = to.to_owned(); "Mutable lend" },
430            Event::MutableBorrow{ from } => { from_ro = Some(from.to_owned()); "Fully borrows resource" },
431            Event::MutableDie{ to } => { to_ro = to.to_owned(); "Fully returns resource"},
432            Event::MutableReacquire{ from } => { from_ro = from.to_owned(); "Fully reacquires resource" },
433            Event::StaticLend{ to } => { to_ro = to.to_owned(); "Partially lends resource" },
434            Event::StaticBorrow{ from } => { from_ro = Some(from.to_owned()); "Partially borrows resource" },
435            Event::StaticDie{ to } => { to_ro = to.to_owned(); "Partially returns resource"},
436            Event::StaticReacquire{ from } => { from_ro = from.to_owned(); "Partially reacquires resource" },
437            Event::InitRefParam{ param: _ } => { "Function parameter is initialized" },
438            Event::OwnerGoOutOfScope => { "Goes out of Scope as an owner of resource" },
439            Event::RefGoOutOfScope => { "Goes out of Scope as a reference to resource" },
440        }.to_string();
441
442        if let Some(from_ro) = from_ro {
443            display = format!("{} from {}", display, &(from_ro.name()));
444        };
445        if let Some(to_ro) = to_ro {
446            display = format!("{} to {}", display, &(to_ro.name()));
447        };
448        write!(f, "{}", display)
449    }
450}
451
452impl Event {
453    pub fn print_message_with_name(&self, my_name: &String) -> String {
454        match self {
455            // no arrow involved
456            OwnerGoOutOfScope => { 
457                hover_messages::event_dot_owner_go_out_out_scope(my_name)
458            }
459            RefGoOutOfScope => {
460                hover_messages::event_dot_ref_go_out_out_scope(my_name)
461            }
462            InitRefParam{ param: _ } => {
463                hover_messages::event_dot_init_param(my_name)
464            }
465            // arrow going out
466            Duplicate{ to } => {
467                safe_message(hover_messages::event_dot_copy_to, my_name, to)
468            }
469            Move{ to } => {
470                match to {
471                    Some(_) => safe_message(hover_messages::event_dot_move_to, my_name, to),
472                    // a Move to None implies the resource is returned by a function
473                    None => safe_message(hover_messages::event_dot_move_to_caller, my_name, to)
474                }
475                
476            }
477            StaticLend{ to } => {
478                safe_message(hover_messages::event_dot_static_lend, my_name, to)
479            }
480            MutableLend{ to } => {
481                safe_message(hover_messages::event_dot_mut_lend, my_name, to)
482            }
483            StaticDie{ to } => {
484                safe_message(hover_messages::event_dot_static_return, my_name, to)
485            }
486            MutableDie{ to } => {
487                safe_message(hover_messages::event_dot_mut_return, my_name, to)
488            }
489            // arrow going in
490            Acquire{ from } => {
491                safe_message(hover_messages::event_dot_acquire, my_name, from)
492            }
493            Copy{ from } => {
494                safe_message(hover_messages::event_dot_copy_from, my_name, from)
495            }
496            MutableBorrow{ from } => {
497                hover_messages::event_dot_mut_borrow(my_name, from.name())
498            }
499            StaticBorrow{ from } => {
500                hover_messages::event_dot_static_borrow(my_name, from.name())
501            }
502            StaticReacquire{ from } => {
503                safe_message(hover_messages::event_dot_static_reacquire, my_name, from)
504            }
505            MutableReacquire{ from } => {
506                safe_message(hover_messages::event_dot_mut_reacquire, my_name, from)
507            }
508        } 
509    }
510}
511
512// a vector of ownership transfer history of a specific variable,
513// in a sorted order by line number.
514#[derive(Debug)]
515pub struct Timeline {
516    pub resource_access_point: ResourceAccessPoint,    // a reference of an Owner or a (TODO) Reference, 
517                                // since Functions don't have a timeline 
518    // line number in usize
519    pub history: Vec<(usize, Event)>,
520}
521
522// a vector of structs information
523#[derive(Debug)]
524pub struct StructsInfo {
525    //struct owner hash, x val of struct owner, x val of the rightmost member
526    pub structs: Vec<(i64, i64, i64)>,
527}
528
529// VisualizationData supplies all the information we need in the frontend,
530// from rendering a PNG to px roducing an interactive HTML guide.
531// The internal data is simple: a map from variable hash to its Timeline.
532#[derive(Debug)]
533pub struct VisualizationData {
534    // When displaying all timelines in the frontend of choice, one should
535    // consider picking a hash function that gives the BTreeMap a sensible order.
536    //      timelines: an orderred map from a Variable's hash to 
537    //      the Variable's Timeline.
538    pub timelines: BTreeMap<u64, Timeline>,
539    
540    pub external_events: Vec<(usize, ExternalEvent)>,
541    //temp container for external_events
542    pub preprocess_external_events: Vec<(usize, ExternalEvent)>,
543    //line_info
544    pub event_line_map: BTreeMap<usize, Vec<ExternalEvent>>,
545}
546
547#[allow(non_snake_case)]
548pub fn ResourceAccessPoint_extract (external_event : &ExternalEvent) -> (&Option<ResourceAccessPoint>, &Option<ResourceAccessPoint>){
549    let (from, to) = match external_event {
550        ExternalEvent::Bind{from: from_ro, to: to_ro} => (from_ro, to_ro),
551        ExternalEvent::Copy{from: from_ro, to: to_ro} => (from_ro, to_ro),
552        ExternalEvent::Move{from: from_ro, to: to_ro} => (from_ro, to_ro),
553        ExternalEvent::StaticBorrow{from: from_ro, to: to_ro} => (from_ro, to_ro),
554        ExternalEvent::StaticDie{from: from_ro, to: to_ro} => (from_ro, to_ro),
555        ExternalEvent::MutableBorrow{from: from_ro, to: to_ro} => (from_ro, to_ro),
556        ExternalEvent::MutableDie{from: from_ro, to: to_ro} => (from_ro, to_ro),
557        ExternalEvent::PassByMutableReference{from: from_ro, to: to_ro} => (from_ro, to_ro),
558        ExternalEvent::PassByStaticReference{from: from_ro, to: to_ro} => (from_ro, to_ro),
559        _ => (&None, &None),
560    };
561    (from, to)
562}
563
564// fulfills the promise that we can support all the methods that a
565// frontend would need.
566impl Visualizable for VisualizationData {
567    fn get_name_from_hash(&self, hash: &u64) -> Option<String> {
568        match self.timelines.get(hash) {
569            Some(timeline) => Some(timeline.resource_access_point.name().to_owned()),
570            _ => None
571        }
572    }
573
574    // if the ResourceAccessPoint is declared mutable
575    fn is_mut(&self, hash: &u64) -> bool {
576        self.timelines[hash].resource_access_point.is_mut()
577    }
578
579    // if the ResourceAccessPoint is a function
580    fn is_mutref(&self, hash: &u64) -> bool {
581        self.timelines[hash].resource_access_point.is_mutref()
582    }
583
584    // a Function does not have a State, so we assume previous_state is always for Variables
585    fn calc_state(&self, previous_state: & State, event: & Event, event_line: usize, hash: &u64) -> State {
586        /* a Variable cannot borrow or return resource from Functions, 
587        but can 'lend' or 'reaquire' to Functions (pass itself by reference and take it back); */
588        fn event_invalid(event: & Event) -> bool {
589            match event {
590                Event::StaticBorrow{ from: ResourceAccessPoint::Function(_) } => true,
591                Event::MutableBorrow{ from: ResourceAccessPoint::Function(_) } => true,
592                Event::StaticDie{ to: Some(ResourceAccessPoint::Function(_)) } => true,
593                Event::MutableDie{ to: Some(ResourceAccessPoint::Function(_)) } => true,
594                _ => false,
595            }
596        }
597        if event_invalid(event) { return State::Invalid; }
598
599        match (previous_state, event) {
600            (State::Invalid, _) =>
601                State::Invalid,
602
603            (State::OutOfScope, Event::Acquire{ .. }) =>
604                State::FullPrivilege,
605
606            (State::OutOfScope, Event::Copy{ .. }) =>
607                State::FullPrivilege,
608
609            (State::OutOfScope, Event::StaticBorrow{ from: ro }) =>
610                State::PartialPrivilege {
611                    borrow_count: 1,
612                    borrow_to: [ro.to_owned()].iter().cloned().collect()
613                },
614
615            (State::OutOfScope, Event::MutableBorrow{ .. }) =>
616                State::FullPrivilege,
617
618            (State::OutOfScope, Event::InitRefParam{ param: ro })  => {
619                match ro {
620                    ResourceAccessPoint::Function(..) => {
621                        panic!("Cannot initialize function as as valid parameter!")
622                    },
623                    ResourceAccessPoint::Owner(..) | ResourceAccessPoint::MutRef(..) => {
624                        State::FullPrivilege
625                    },
626                    ResourceAccessPoint::Struct(..) => {
627                        State::FullPrivilege
628                    },
629                    ResourceAccessPoint::StaticRef(..) => {
630                        State::PartialPrivilege {
631                            borrow_count: 1,
632                            borrow_to: [ro.to_owned()].iter().cloned().collect()
633                        }
634                    }
635                }
636            },
637
638            (State::FullPrivilege, Event::Move{to: to_ro}) =>
639                State::ResourceMoved{ move_to: to_ro.to_owned(), move_at_line: event_line },
640
641            (State::ResourceMoved{ .. }, Event::Acquire{ .. }) => {
642                if self.is_mut(hash) {
643                    State::FullPrivilege
644                }
645                else { // immut variables cannot reacquire resource
646                    eprintln!("Immutable variable {} cannot reacquire resources!", self.get_name_from_hash(hash).unwrap());
647                    std::process::exit(1);
648                }
649            },
650
651            (State::FullPrivilege, Event::MutableLend{ to: to_ro }) => {
652            // Assumption: variables can lend mutably if
653            // 1) variable instance is mutable or 2) variable is a mutable reference
654            // Use cases: 'mutable_borrow' & 'nll_lexical_scope_different'
655                if self.is_mut(hash) | self.is_mutref(hash) {
656                    State::RevokedPrivilege{ to: None, borrow_to: to_ro.to_owned() }
657                } else {
658                    State::Invalid
659                }
660            },
661            
662            // happends when a mutable reference returns, invalid otherwise
663            (State::FullPrivilege, Event::MutableDie{ .. }) =>
664                State::OutOfScope,
665
666            (State::FullPrivilege, Event::Acquire{ from: _ }) | (State::FullPrivilege, Event::Copy{ from: _ }) => {
667                if self.is_mut(hash) {
668                    State::FullPrivilege
669                }
670                else {
671                    State::Invalid
672                }
673            },
674
675            (State::FullPrivilege, Event::OwnerGoOutOfScope) =>
676                State::OutOfScope,
677
678            (State::FullPrivilege, Event::RefGoOutOfScope) =>
679                State::OutOfScope,
680
681            (State::FullPrivilege, Event::StaticLend{ to: to_ro }) =>
682                State::PartialPrivilege {
683                    borrow_count: 1,
684                    borrow_to: [(to_ro.to_owned().unwrap())].iter().cloned().collect() // we assume there is no borrow_to:None
685                },
686
687            (State::PartialPrivilege{ .. }, Event::MutableLend{ .. }) =>
688                State::Invalid,
689
690            (State::PartialPrivilege{ borrow_count: current, borrow_to }, Event::StaticLend{ to: to_ro }) => {
691                let mut new_borrow_to = borrow_to.clone();
692                // Assume can not lend to None
693                new_borrow_to.insert(to_ro.to_owned().unwrap());
694                State::PartialPrivilege {
695                    borrow_count: current+1,
696                    borrow_to: new_borrow_to,
697                }
698            }
699                
700            // self statically borrowed resource, and it returns; TODO what about references to self?
701            (State::PartialPrivilege{ .. }, Event::StaticDie{ .. }) =>
702                State::OutOfScope,
703
704            (State::PartialPrivilege{ borrow_count, borrow_to }, Event::StaticReacquire{ from: ro }) => {
705                let new_borrow_count = borrow_count - 1;
706                // check if it resumes to full privilege    
707                if borrow_count - 1 == 0 {
708                        State::FullPrivilege 
709                    } else {
710                        let mut new_borrow_to = borrow_to.clone();
711                        // TODO ro.unwrap() should not panic, because Reacquire{from: None} is not possible
712                        // TODO change to Reaquire{from: ResourceAccessPoint}
713                        assert_eq!(new_borrow_to.remove(&ro.to_owned().unwrap()), true); // borrow_to must contain ro
714                        State::PartialPrivilege{
715                            borrow_count: new_borrow_count,
716                            borrow_to: new_borrow_to,
717                        }
718                    }
719                }
720
721            (State::PartialPrivilege{ .. }, Event::OwnerGoOutOfScope) =>
722                State::OutOfScope,
723
724            (State::PartialPrivilege{ .. }, Event::RefGoOutOfScope) =>
725                State::OutOfScope,
726
727            (State::RevokedPrivilege{ .. }, Event::MutableReacquire{ .. }) =>
728                State::FullPrivilege,
729
730            (_, Event::Duplicate { .. }) =>
731                (*previous_state).clone(),
732
733            (_, _) => State::Invalid,
734        }
735    }
736
737    fn get_states(&self, hash: &u64) -> Vec::<(usize, usize, State)> {
738        let mut states = Vec::<(usize, usize, State)>::new();
739        let mut previous_line_number: usize = 1;
740        let mut prev_state = State::OutOfScope;
741        for (line_number, event) in self.timelines[hash].history.iter() {
742            states.push(
743                (previous_line_number, *line_number, prev_state.clone())
744            );
745            prev_state = self.calc_state(&prev_state, &event, *line_number, hash);
746            previous_line_number = *line_number;
747        }
748        states.push(
749            (previous_line_number, previous_line_number, prev_state.clone())
750        );
751        states
752    }
753
754    fn get_state(&self, hash: &u64, _line_number: &usize) -> Option<State> {
755        // TODO: the line_number variable should be used to determine state here
756        match self.timelines.get(hash) {
757            Some(_timeline) => {
758                // example return value
759                Some(State::OutOfScope)
760            },
761            _ => None
762        }
763    }
764
765    fn append_external_event(&mut self, event: ExternalEvent, line_number: &usize) {
766        // push in preprocess_external_events
767        self.preprocess_external_events.push((*line_number, event.clone()));
768        //------------------------construct external event line info----------------------
769        let resourceaccesspoint = ResourceAccessPoint_extract(&event);
770        match (resourceaccesspoint.0, resourceaccesspoint.1, &event) {
771            (Some(ResourceAccessPoint::Function(_)), Some(ResourceAccessPoint::Function(_)), _) => {
772                // do nothing case
773            },
774            (Some(ResourceAccessPoint::Function(_from_function)), Some(_to_variable), _) => {  
775                // (Some(function), Some(variable), _)
776            },
777            (Some(_from_variable), Some(ResourceAccessPoint::Function(_function)), 
778             ExternalEvent::PassByStaticReference{..}) => { 
779                 // (Some(variable), Some(function), PassByStatRef)
780            },
781            (Some(_from_variable), Some(ResourceAccessPoint::Function(_function)), 
782             ExternalEvent::PassByMutableReference{..}) => {  
783                 // (Some(variable), Some(function), PassByMutRef)
784            },
785            (Some(_from_variable), Some(ResourceAccessPoint::Function(_to_function)), _) => { 
786                // (Some(variable), Some(function), _)
787            },
788            (Some(_from_variable), Some(_to_variable), _) => {
789                if let Some(event_vec) = self.event_line_map.get_mut(&line_number) {
790                    // Q: do I have to dereference here? Only derefernece case is Box<>
791                    // Q: do I have to clone this? like store reference?
792                    event_vec.push(event);
793                } else {
794                    let vec = vec![event];
795                    self.event_line_map.insert(line_number.clone(), vec);
796                }
797            },
798            _ => ()
799        }
800    }
801
802    // WARNING do not call this when making visualization!! 
803    // use append_external_event instead
804    fn _append_event(&mut self, resource_access_point: &ResourceAccessPoint, event: Event, line_number: &usize) {
805        let hash = &resource_access_point.hash();
806        // if this event belongs to a new ResourceAccessPoint hash,
807        // create a new Timeline first, thenResourceAccessPoint bind it to the corresponding hash.
808        match self.timelines.get(hash) {
809            None => {
810                let timeline = Timeline {
811                    resource_access_point: resource_access_point.clone(),
812                    history: Vec::new(),
813                };
814                self.timelines.insert(**hash, timeline);
815            },
816            _ => {}
817        }
818
819        // append the event to the end of the timeline of the corresponding hash
820        match self.timelines.get_mut(hash) {
821            Some(timeline) => {
822                timeline.history.push(
823                    (*line_number, event)
824                );
825            },
826            _ => {
827                panic!("Timeline disappeared right after creation or when we could index it. This is impossible.");
828            }
829        }
830    }
831
832
833    // store them in external_events, and call append_events
834    // default way to record events
835    fn append_processed_external_event(&mut self, event: ExternalEvent, line_number: usize) {
836        self.external_events.push((line_number, event.clone()));
837        
838        // append_event if resource_access_point is not null
839        fn maybe_append_event(vd: &mut VisualizationData, resource_access_point: &Option<ResourceAccessPoint>, event: Event, line_number : &usize) {
840            if let Some(ro) = resource_access_point {
841                vd._append_event(&ro, event, line_number)
842            };
843        }
844
845        match event {
846            // eg let ro_to = String::from("");
847            ExternalEvent::Move{from: from_ro, to: to_ro} => {
848                maybe_append_event(self, &to_ro, Event::Acquire{from : from_ro.to_owned()}, &line_number);
849                maybe_append_event(self, &from_ro, Event::Move{to : to_ro.to_owned()}, &line_number);
850            },
851            // eg: let ro_to = 5;
852            ExternalEvent::Bind{from: from_ro, to: to_ro} => {
853                maybe_append_event(self, &to_ro, Event::Acquire{from : from_ro.to_owned()}, &line_number);
854                maybe_append_event(self, &from_ro, Event::Duplicate{to : to_ro.to_owned()}, &line_number);
855            },
856            // eg: let x : i64 = y as i64;
857            ExternalEvent::Copy{from: from_ro, to: to_ro} => {
858                maybe_append_event(self, &to_ro, Event::Copy{from : from_ro.to_owned()}, &line_number);
859                maybe_append_event(self, &from_ro, Event::Duplicate{to : to_ro.to_owned()}, &line_number);
860            },
861            ExternalEvent::StaticBorrow{from: from_ro, to: to_ro} => {
862                maybe_append_event(self, &from_ro, Event::StaticLend{to : to_ro.to_owned()}, &line_number);
863                if let Some(some_from_ro) = from_ro {
864                    maybe_append_event(self, &to_ro, Event::StaticBorrow{from : some_from_ro.to_owned()}, &line_number);
865                }
866            },
867            ExternalEvent::StaticDie{from: from_ro, to: to_ro} => {
868                maybe_append_event(self, &to_ro, Event::StaticReacquire{from : from_ro.to_owned()}, &line_number);
869                maybe_append_event(self, &from_ro, Event::StaticDie{to : to_ro.to_owned()}, &line_number);
870            },
871            ExternalEvent::MutableBorrow{from: from_ro, to: to_ro} => {
872                maybe_append_event(self, &from_ro, Event::MutableLend{to : to_ro.to_owned()}, &line_number);
873                if let Some(some_from_ro) = from_ro {
874                    maybe_append_event(self, &to_ro, Event::MutableBorrow{from : some_from_ro.to_owned()}, &line_number);
875                }
876            },
877            ExternalEvent::MutableDie{from: from_ro, to: to_ro} => {
878                maybe_append_event(self, &to_ro, Event::MutableReacquire{from : from_ro.to_owned()}, &line_number);
879                maybe_append_event(self, &from_ro, Event::MutableDie{to : to_ro.to_owned()}, &line_number);
880            },
881            // TODO do we really need to add these events, since pass by ref does not change the state?
882            ExternalEvent::PassByStaticReference{from: from_ro, to: to_ro} => {
883                maybe_append_event(self, &from_ro.to_owned(), Event::StaticLend{to : to_ro.to_owned()}, &line_number);
884                if let Some(some_from_ro) = from_ro.to_owned() {
885                    maybe_append_event(self, &to_ro.to_owned(), Event::StaticBorrow{from : some_from_ro.to_owned()}, &line_number);
886                } else {
887                    eprintln!("Must pass a function to PassByStaticReference.to!");
888                    std::process::exit(1);
889                }
890                maybe_append_event(self, &from_ro, Event::StaticReacquire{from : to_ro.to_owned()}, &line_number);
891                maybe_append_event(self, &to_ro, Event::StaticDie{to : from_ro.to_owned()}, &line_number);
892            },
893            ExternalEvent::PassByMutableReference{from: from_ro, to: to_ro} => {
894                maybe_append_event(self, &from_ro, Event::MutableLend{to : to_ro.to_owned()}, &line_number);
895                if let Some(some_from_ro) = from_ro.to_owned() {
896                    maybe_append_event(self, &to_ro, Event::MutableBorrow{from : some_from_ro.to_owned()}, &line_number);
897                } else {
898                    eprintln!("Must pass a function to PassByMutableReference.to!");
899                    std::process::exit(1);
900                }
901                maybe_append_event(self, &from_ro, Event::MutableReacquire{from : to_ro.to_owned()}, &line_number);
902                maybe_append_event(self, &to_ro, Event::MutableDie{to : from_ro.to_owned()}, &line_number);
903            },
904            ExternalEvent::InitRefParam{param: ro} => {
905                maybe_append_event(self, &Some(ro.clone()), Event::InitRefParam{param : ro.to_owned()}, &line_number);
906            },
907            ExternalEvent::GoOutOfScope{ro} => {
908                match ro {
909                    ResourceAccessPoint::Owner(..) => {
910                        maybe_append_event(self, &Some(ro), Event::OwnerGoOutOfScope, &line_number);
911                    },
912                    ResourceAccessPoint::Struct(..) => {
913                        maybe_append_event(self, &Some(ro), Event::OwnerGoOutOfScope, &line_number);
914                    },
915                    ResourceAccessPoint::MutRef(..) => {
916                        maybe_append_event(self, &Some(ro), Event::RefGoOutOfScope, &line_number);
917                    },
918                    ResourceAccessPoint::StaticRef(..) => {
919                        maybe_append_event(self, &Some(ro), Event::RefGoOutOfScope, &line_number);
920                    },
921                    ResourceAccessPoint::Function(func) => {
922                        println!(
923                            "Functions do not go out of scope! We do not expect to see \"{}\" here.",
924                            func.name
925                        );
926                        std::process::exit(1);
927                    }
928                }
929            },
930        }
931    }
932}
933
934/* TODO use this function to create a single copy of resource owner in resource_access_point_map,
935 and use hash to refer to it */ 
936// impl VisualizationData {
937//     fn create_resource_access_point(&mut self, ro: ResourceAccessPoint) -> &ResourceAccessPoint {
938//         self.resource_access_point_map.entry(ro.get_hash()).or_insert(ro);
939//         self.resource_access_point_map.get(ro.get_hash())
940//     }
941// }