1     type String @abstract =
2         let mut display = StringBuilder.new
3         let mut staging = StringBuilder.new
4         var is_constant = false
5         let mut is_deferred = false
6         var is_invoking_callbacks = false
7         let callbacks = StdList<StdString * StdString -> Unit>.new
8     
9         def as_string = display.as_string
10        def length = display.length
11        def has_callbacks = callbacks.is_not_empty
12        def is_empty = length == 0
13        def is_not_empty = length <> 0
14    
15        def subscribe (f : StdString * StdString -> Unit) =
16            assert not is_invoking_callbacks
17            callbacks.add f
18    
19            Token { assert not is_invoking_callbacks
20                    callbacks.remove f }
21    
22        fun destruct =
23            assert callbacks.is_empty
24    
25    type MutString @[mut_of String] =
26        inherit String
27    
28        let invoke_callbacks () =
29            assert not is_invoking_callbacks
30            is_invoking_callbacks = true
31            let s = display.as_string
32            let prev_s = staging.as_string
33    
34            for f in callbacks do
35                f prev_s s
36    
37            is_invoking_callbacks = false
38    
39        let commit () =
40            if is_deferred then
41                return
42    
43            assert not is_constant
44            let s = display
45            display = staging
46            staging = s
47            invoke_callbacks
48            staging.clear
49            staging.append display.as_string
50    
51        def as_readonly = self as String
52    
53        def set (s : StdString) =
54            if s <> display.as_string then
55                staging.clear
56                staging.append s
57                commit
58    
59        def make_constant =
60            assert not is_constant
61            is_constant = true
62    
63        def defer_commits =
64            assert not is_deferred
65            is_deferred = true
66    
67        def resume_commits =
68            assert is_deferred
69            is_deferred = false
70            if display.as_string <> staging.as_string then
71                commit
72    
73        def insert (index : u32) (c : Char) =
74            staging.insert index c
75            commit
76    
77        def insert (index : u32) (s : StdString) =
78            staging.insert index s
79            commit
80    
81        def replace (start : u32
82                     end : u32
83                     s : StdString) =
84            staging.replace_range start end s
85            commit
86    
87        def append (s : StdString) =
88            staging.append s
89            commit
90    
91        def remove_at (index : u32) =
92            staging.remove_at index
93            commit
94    
95        def remove_range (index : u32) (count : u32) =
96            staging.remove_range index (index + count)
97            commit
98    
99        def clear =
100           staging.clear
101           commit
102   
103   object String =
104       def from_str (s : StdString) =
105           let string = String.new
106           string.set s
107   
108           string
109