1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#![feature(new_uninit, ptr_as_uninit, pattern)]
#![deny(unsafe_op_in_unsafe_fn)]

//!
// Important: note the blank line of documentation on each side of the image lookup table.
// The "image lookup table" can be placed anywhere, but we place it here together with the
// warning if the `doc-images` feature is not enabled.
#![cfg_attr(feature = "doc-images",
    cfg_attr(all(),
    doc = ::embed_doc_image::embed_image!("ex1", "images/char_list_ex_1.svg"),
    doc = ::embed_doc_image::embed_image!("ex2", "images/char_list_ex_2.svg"),
    doc = ::embed_doc_image::embed_image!("ex3", "images/char_list_ex_3.svg"),
    doc = ::embed_doc_image::embed_image!("ex4", "images/char_list_ex_4.svg"),
))]
#![cfg_attr(
    not(feature = "doc-images"),
    doc = "**Doc images not enabled**. Compile with feature `doc-images` and Rust version >= 1.54 \
           to enable."
)]
//!
//! A persistent string type with the same API as a linked-list of characters.
//! ## Contents
//! ### `FiniteCharList`
//! The `FiniteCharList` type is probably what you want to use. It behaves just
//! like a linked list of characters but with better (TODO: verify) performance.
//!
//! ## `CharList<Tail>`
//! The `CharList<Tail>` type allows customization of the data structure by
//! allowing a custom tail. I'm using this to emulate Prolog's open-ended lists
//! where the tail of the list may be an uninstantiated Prolog variable.
//!
//! A `FiniteCharList` is just a type alias for `CharList<()>`.
//!
//! Generic `CharList`s have much fewer abilities provided by this crate because
//! the nature of the tail is unknown. For instance, `CharList<Tail>` does *not*
//! implement `AsRef<str>` or even `PartialEq`!
//!
//! The intention is that you will wrap a `CharList<YourTail>` in a newtype and
//! implement those traits if it makes sense for your problem space. For
//! example, I (plan to) use a `CharList<ast::Expression>` which *will*
//! implement `PartialEq` because I want syntactic equality.
//!
//! ## DISCLAIMER: `unsafe`
//! This crate is a work in progress. Specifically ***Not all uses of `unsafe`
//! have been validated!*** Please don't use this for anything serious yet.
//!
//! Safety audits are welcome and appreciated! I'm still quite new to writing
//! `unsafe` code.
//!
//! Also, this crate depends on [`front-vec`](https://crates.io/crates/front-vec)
//! which is also badly in need of auditing.
//!
//! ## Internal Representation
//! This crate relies on [`front_vec::FrontString`](https://docs.rs/front-vec/latest/front_vec/struct.FrontString.html) to store arrays of bytes which allow for
//! efficient prepending (pushing characters onto the front of the array).
//!
//! Each `FrontString` is owned by a `PqRcCell` (internal to this crate, soon
//! to be it's own crate) which is sorta like a cross between a `RefCell` and a
//! `RcBox` (the thing an `Rc` pointer points to).
//!
//! A `CharList` is just a pointer + length (though it's not a slice) which
//! refers to a specific slice of a `PqRcCell`-managed `FrontString`.
//!
//! The `PqRcCell` ensures that out of all `CharList`s which refer to it's
//! `FrontString`, only those with the **longest length** are allowed to mutate
//! the inner `FrontString` value. And they can only\* mutate it in ways that
//! other `CharList`s won't notice.
//!
//! \* (Ok, at this point we make developers pinky-swear 🤞 they'll follow those
//! rules, and they gotta wrap their use in an `unsafe` block. Maybe there's a
//! better way to do this in the future though 🤔)
//!
//! That was a lotta words, let's look at an example with memory diagrams.
//!
//! ### Memory Diagram
//!
//! #### Note: Simplified Diagrams
//! Every time the word `len` or `refs` appears in these diagrams, in the code
//! it corresponds to either `priority` or `priorities`. The internal
//! representation of a `CharList` is actually just a `PqRc` (Priority Queue
//! Reference Counted) pointer which abstracts over its priority. For
//! `CharList`s, priority is the same as string length.
//!
//! #### Example
//! Consider this code:
//!
//! ```
//! # use char_list::FiniteCharList;
//! use assert2::assert; // For nicer assertions.
//! let icon = FiniteCharList::from("icon");
//! let nomicon = icon.cons_str("nom");
//! let rustonomicon = nomicon.cons_str("rusto");
//! let rustonomicon2 = rustonomicon.clone();
//!
//! assert!(icon == "icon");
//! assert!(nomicon == "nomicon");
//! assert!(rustonomicon == "rustonomicon");
//! assert!(rustonomicon == rustonomicon2);
//! ```
//!
//! These values would be represented in memory like this:
//!
//! ![did it work?][ex1]
//!
//! (The arrows with dashed lines represent the *implied* beginnings of
//! `CharList` slices, i.e. `icon` implicitly "refers to" the last four bytes
//! in the buffer.)
//!
//! Notice that all `cons_str` and `clone` operations are immutable, i.e. they
//! create new `CharList`s instead of mutating the original.
//!
//! #### One More `cons`
//!
//! ```
//! # use char_list::FiniteCharList;
//! # use assert2::assert;
//! # let icon = FiniteCharList::from("icon");
//! # let nomicon = icon.cons_str("nom");
//! # let rustonomicon = nomicon.cons_str("rusto");
//! # let rustonomicon2 = rustonomicon.clone();
//! #
//! # assert!(icon == "icon");
//! # assert!(nomicon == "nomicon");
//! # assert!(rustonomicon == "rustonomicon");
//! # assert!(rustonomicon == rustonomicon2);
//! #
//! let the_book = rustonomicon.cons_str("the ");
//! assert!(the_book == "the rustonomicon");
//! ```
//!
//! Here's what memory looks like now:
//!
//! ![did it work?][ex2]
//!
//! Because `rustonomicon` has the longest length in the `refs` table, it's
//! perfectly safe to call the underlying `FrontString`'s `push_char_front`
//! method (mutably!).
//!
//! Notice that by pushing a character onto the front, `rustonomicon` doesn't
//! affect **any other `CharList`'s view** of the underlying `FrontString`.
//!
//! #### Dropping
//!
//! Ok now what happens if we `drop` the longest three `CharList`s?
//!
//! ```
//! # use char_list::FiniteCharList;
//! # use assert2::assert;
//! # let icon = FiniteCharList::from("icon");
//! # let nomicon = icon.cons_str("nom");
//! # let rustonomicon = nomicon.cons_str("rusto");
//! # let rustonomicon2 = rustonomicon.clone();
//! #
//! # assert!(icon == "icon");
//! # assert!(nomicon == "nomicon");
//! # assert!(rustonomicon == "rustonomicon");
//! # assert!(rustonomicon == rustonomicon2);
//! #
//! # let the_book = rustonomicon.cons_str("the ");
//! # assert!(the_book == "the rustonomicon");
//! #
//! drop(rustonomicon);
//! drop(the_book);
//! drop(rustonomicon2);
//! ```
//!
//! ![did it work?][ex3]
//!
//! Notice that the internal `FrontString`'s `len` went down to 7. This means
//! we can reuse the memory that used to be held by the longer strings!
//!
//! #### Tricky `cons`
//!
//! Here's a problem though. What if we want to `cons` the character `'b'` onto
//! the front of `icon`?
//!
//! ```
//! # use char_list::FiniteCharList;
//! # use assert2::assert;
//! # let icon = FiniteCharList::from("icon");
//! # let nomicon = icon.cons_str("nom");
//! # let rustonomicon = nomicon.cons_str("rusto");
//! # let rustonomicon2 = rustonomicon.clone();
//! #
//! # assert!(icon == "icon");
//! # assert!(nomicon == "nomicon");
//! # assert!(rustonomicon == "rustonomicon");
//! # assert!(rustonomicon == rustonomicon2);
//! #
//! # let the_book = rustonomicon.cons_str("the ");
//! # assert!(the_book == "the rustonomicon");
//! #
//! # drop(rustonomicon);
//! # drop(the_book);
//! # drop(rustonomicon2);
//! #
//! let janelle_monae = icon.cons('b');
//! assert!(janelle_monae == "bicon");
//! ```
//!
//! Well, if we overwrite the `'m'` that currently sits in front of "icon",
//! we'd be modifying `nomicon`'s view of the string. That's no good, so we
//! gotta **clone** `icon`'s view of the `FrontString` and mutate the copy.
//!
//! ![did it work?][ex4]
//!

mod char_list;
mod pq_rc;

pub use crate::char_list::finite::FiniteCharList;
pub use crate::char_list::*;