aboutsummaryrefslogtreecommitdiff
path: root/std/prelude/strings.pk
diff options
context:
space:
mode:
authorJJ2024-05-10 01:00:01 +0000
committerJJ2024-05-10 02:41:52 +0000
commit073c902a31936c2b53d89245662fb272c9670169 (patch)
treea8789ed4561dc4c3dde84489a600272cbd5f806b /std/prelude/strings.pk
parent51c8b349a77a8d8b1b34ce8e03518dad6e3cba00 (diff)
std: sweeping changes.
- replace interfaces with classes - replace : with then and do - solidify memory management as rust-style ownership - replace unsafe blocks with safe/unsafe attributes - add magic and copy attributes - switch Coerce impl from from to to
Diffstat (limited to 'std/prelude/strings.pk')
-rw-r--r--std/prelude/strings.pk104
1 files changed, 43 insertions, 61 deletions
diff --git a/std/prelude/strings.pk b/std/prelude/strings.pk
index 2f48b67..e86d520 100644
--- a/std/prelude/strings.pk
+++ b/std/prelude/strings.pk
@@ -2,100 +2,82 @@
## This module is imported by default.
# reference: https://doc.rust-lang.org/std/string/struct.String.html
-use std.pointers
-
-# possible approaches: list[byte], distinct list[byte], this
-# should *really* just rely on lists, i don't want to duplicate slicing logic, but... maybe...
-type str = struct
- data: ptr[byte]
- length: uint
- capacity: uint
+## A primitive string type.
+##
+## We do not want methods defined on `list[byte]` to carry over,
+## so we define `str` as a newtype.
+pub type str = struct
+ data: list[byte]
## Initialize and return an empty string.
-pub func init(): str =
- ...
+pub func init: str = { data = [] }
## Gets the length of a string.
-pub func len(self: str): uint =
- self.length
-
-pub func empty(self: str): bool =
- self.length == 0
-
-## Gets the internal capacity of a string.
-func cap(self: str): uint =
- self.capacity
-
-## Expands the capacity of a string.
-func grow(self: mut str) =
- ...
+## This is an O(n) operation, due to UTF-8 encoding.
+pub func len(self: lent str): uint =
+ var res: uint
+ for _ in self do
+ res += 1
+ res
## Pushes a character to the end of a mutable string.
-pub func push(self: mut str, val: chr) = # todo: `add` alias?
- ...
+pub func push(self: mut str, val: chr) =
+ self.data.push(val.byte) # todo: obsolete by from/to conversion??
## Pushes an owned string to the end of a mutable string.
pub func push(self: mut str, val: str) =
- ...
+ self.data.push(val.bytes) # todo: obsolete by from/to conversion??
## Removes and returns the last character of a string, if it exists.
+##
+## SAFETY: We return early upon an empty string.
+## And decrement by one char for a non-empty string.
+@[safe]
pub func pop(self: mut str): chr? =
- ...
+ let char = self.chars.rev.next?
+ self.data.set_len(self.len - char.len) # this is normally unsafe.
+ Some(char)
## Returns the character at the provided index, if it exists.
pub func get(self: str, i: uint): chr? =
...
## Sets the character at the provided index, if it exists.
-## todo: what if it does not exist?
+## As strings are packed, this may call str.grow and reallocate.
+## oh fuck we have to insert + remove anyway
pub func set(self: mut str, i: uint, val: chr) =
...
## Inserts a character at an arbitrary position within a string.
-## Error handling: todo
+## Panics on failure. (todo: can we do better?)
pub func insert(self: mut str, i: uint, val: chr) =
...
## Removes and returns a character at an arbitrary position within a string.
-## Panics on failure.
+## Panics on failure. (todo: can we do better?)
pub func remove(self: mut str, i: uint): chr =
...
-## Returns the *byte* at an arbitrary position within a string.
-## Explicitly distinct from `get` as this breaks safety conventions idk
-pub func get_byte(self: str): byte =
- ...
-
-## Sets a byte at the provided index, if it exists. Do we want this?
-pub func set_byte(self: mut str, i: uint, val: byte) =
- ...
-
-## Inserts a byte into a string. Breaks string convention. Do we want this?
-pub func insert_byte(self: mut str, i: uint, val: byte) =
- ...
-
-## Removes a byte at a given offset from a string. Do we want this?
-pub func remove_byte(self: mut str, i: uint): byte? =
- ...
-
-## Converts a given string to a list of bytes for iteration purposes.
-pub func bytes(self: str): list[byte] =
- ... # many performance considerations
-
-## Converts a given string to a list of chars for iteration purposes.
-pub func chars(self: str): list[chr] # todo: useful?
-
-## The concatenation operator.
-pub func &(a: str, b: str): str =
- ...
-
## Syntactic sugar for string appending.
-pub func &=(a: mut str, b: owned str) =
+pub func &=(a: mut str, b: str) =
a.push(b)
-# todo: many things
+## The concatenation operator. Consumes two strings.
+pub func &(a: str, b: str): str =
+ a.push(b)
+ a
+
+## Conversion from a string to a list of bytes. Zero-cost.
+pub func to(self: str): list[byte] = self.data
+## Conversion from a str to a list[chr]. Reallocates.
+pub func to(self: str): list[chr] =
+ var res: list[chr]
+ for char in self do res.push(char)
+ res
+## Conversion from a char to an array of bytes. Zero-cost.
+@[safe] # possibly unsafe?? depends on repr of arrays
+pub func to(self: chr): array[byte, 4] = self.cast[array[byte, 4]]
-# pub func iter(self: str): StrIter
# pub func next(self: mut StrIter)
# pub func peek(self: mut StrIter)
# pub func peek_nth(self: mut StrIter, i: uint)