No matching definitions.

tur/string

stdlib/string.tur

owned, immutable, refcounted String.

Unlike cstr (a borrowed raw const char* with no length or ownership) and str (a borrowed pointer+length view), a String OWNS its bytes: it is a refcounted immutable heap payload { rc; len; bytes[len+1] }, NUL-terminated so a borrowed cstr view is O(1). Reach for String when a string must outlive its source -- a value returned past its buffer, a stored field, or a Map/Set key. As a MapKey the map copies and owns the key bytes (mk-owned? = 1), so a String key never dangles the way a computed cstr key does.

String is immutable; every transform returns a fresh String. Build one incrementally with StringBuilder so repeated concatenation stays linear.

Since: v2 (owned-string-type-plan)

defopaque

String

(defopaque String :ptr<void> :non-null)
defopaque

StringBuilder

(defopaque StringBuilder :ptr<void> :non-null)
defn

string/from-cstr

(string/from-cstr [s :cstr] :String)

copy a NUL-terminated C string into a fresh owned String.

sthe source cstr (a literal or borrowed buffer); its bytes are copied

A new String (refcount 1) owning a private copy of s's bytes.

(string/from-cstr "hello")  ; => String "hello"

Since: v2

defn

string/to-cstr

(string/to-cstr [s :String] :cstr)

borrow the String's NUL-terminated bytes (O(1), no copy).

The returned cstr points into the String's payload and stays valid only while the String is retained; do not use it after the String is released.

sthe String to borrow from

A borrowed cstr view of the same bytes.

(string/to-cstr (string/from-cstr "hi"))  ; => "hi"

Since: v2

defn

string/adopt-cstr

(string/adopt-cstr [s :cstr] :String)

take ownership of a freshly-allocated cstr as a String.

Copies the bytes of s into a fresh owned String and FREES s. This is the owned-adoption bridge for the many stdlib functions that return a malloc'd cstr ("caller frees the result") -- wrap such a call in string/adopt-cstr and the result is a real owned String, leak-free:

(string/adopt-cstr (path/join base seg))   ; owned path String
(string/adopt-cstr (digest/sha256-hex ...)) ; owned digest String

WARNING: s MUST be a heap buffer the caller owns. Never pass a string literal or a borrowed cstr (an accessor's return, a struct field) -- freeing that is undefined behavior. When in doubt, use string/from-cstr (which copies without freeing).

sa freshly heap-allocated NUL-terminated cstr; consumed (freed)

A new owned String holding a copy of s's bytes.

Since: v2 (string-adoption-stdlib-plan, batch 1)

defn

int->string

(int->string [v :int] :String)

format a signed integer as a fresh owned decimal String.

The owned counterpart of int->str (which returns a caller-frees cstr); builds the String directly with no cstr intermediate.

vthe integer to render

A new owned String, e.g. (int->string -7) => String "-7".

(string/to-cstr (int->string 42))  ; => "42"

Since: v2 (string-adoption-stdlib-plan, batch 1)

defn

string/retain

(string/retain [s :String] :String)

increment the refcount, returning a second owning handle.

Since: v2

defn

string/release

(string/release [s :String] :void)

decrement the refcount; free the payload at zero.

Since: v2

defn

string/len

(string/len [s :String] :int)

byte length of the String (not counting the NUL).

Since: v2

defn

string/empty?

(string/empty? [s :String] :bool)

true iff the String has length zero.

Since: v2

defn

string/byte-at

(string/byte-at [s :String i :int] :int)

the byte (0..255) at index i, or -1 if out of range.

Since: v2

defn

string/byte-is?

(string/byte-is? [s :String i :int c :Char] :bool)

is the byte at index i the character c?

The bounds-checked test a byte scanner needs: false when i is out of range, so it replaces (if (< i (string/len s)) (= (string/byte-at s i) 44) false) and the magic number with it. It compares one byte with c's code, so c should be ASCII; a character whose code is above 127 is several bytes in UTF-8 and is not what this finds.

sthe String to look in (borrowed)
ia byte index; out of range is not an error
cthe character to compare with

true iff 0 <= i < (string/len s) and the byte at i is c's code.

(string/byte-is? (string/from-cstr "a,b") 1 #\,)  ; => true

Since: markdown-library-plan S1

defn

string/char-at

(string/char-at [s :String i :int] :(Option Char))

the byte at index i as a Char, or (none) out of range.

For byte-at-a-time scanning that wants to compare with character literals: (match (string/char-at s i) (Some c) (eq? c #\#) (None) false). The Char is the raw byte (0..255); decoding UTF-8 is a separate step.

sthe String to look in (borrowed)
ia byte index; out of range is not an error

(some c) holding the byte at i, or (none) when i is out of range.

(string/char-at (string/from-cstr "hi") 1)  ; => (some #\i)

Since: markdown-library-plan S1

defn

string/eq?

(string/eq? [a :String b :String] :bool)

content equality (length then byte compare).

Since: v2

defn

string/compare

(string/compare [a :String b :String] :int)

lexicographic byte compare: -1, 0, or 1.

Since: v2

defn

string/hash

(string/hash [s :String] :int)

content hash over the exact byte range (length-aware).

Since: v2

defn

string/starts-with?

(string/starts-with? [s :String prefix :String] :bool)

true iff s begins with prefix.

Since: v2

defn

string/ends-with?

(string/ends-with? [s :String suffix :String] :bool)

true iff s ends with suffix.

Since: v2

defn

string/contains?

(string/contains? [s :String needle :String] :bool)

true iff needle occurs as a substring of s.

Since: v2

defn

string/-match-at

(string/-match-at [s :String p :String at :int k :int n :int] :bool)

internal: do bytes [k, n) of p equal s's from at+k on?

defn

string/starts-with-at?

(string/starts-with-at? [s :String prefix :String at :int] :bool)

does prefix occur in s at byte offset at?

string/starts-with? at any offset: the test a scanner makes before it consumes a token. An offset out of range, or a prefix that would run past the end of s, gives false, not an error. The empty prefix occurs at every offset from 0 to (string/len s).

sthe String to look in (borrowed)
prefixthe bytes to look for (borrowed)
atthe byte offset in s to test

true iff the bytes of s from at on begin with prefix.

(string/starts-with-at? (string/from-cstr "a --> b") (string/from-cstr "-->") 2)  ; => true

Since: markdown-library-plan S2

defn

string/-index-of-loop

(string/-index-of-loop [s :String needle :String i :int last :int] :(Option int))

internal: first match of needle at i..last.

defn

string/index-of-from

(string/index-of-from [s :String needle :String start :int] :(Option int))

byte offset of the first needle at or after start.

A negative start searches from 0; a start past the end finds nothing. The empty needle is found at start itself, while start <= (string/len s).

sthe String to search (borrowed)
needlethe bytes to find (borrowed)
startthe first byte offset a match may begin at

(some i) for the lowest i >= start where needle occurs, else (none).

(string/index-of-from (string/from-cstr "a,b,c") (string/from-cstr ",") 2)  ; => (some 3)

Since: markdown-library-plan S2

defn

string/index-of

(string/index-of [s :String needle :String] :(Option int))

byte offset of the first occurrence of needle in s.

sthe String to search (borrowed)
needlethe bytes to find (borrowed)

(some i) for the lowest i where needle occurs, or (none). The empty needle is found at 0.

(string/index-of (string/from-cstr "key: value") (string/from-cstr ": "))  ; => (some 3)

Since: markdown-library-plan S2

defn

string/-last-index-of-loop

(string/-last-index-of-loop [s :String needle :String i :int] :(Option int))

internal: last match of needle at i down to 0.

defn

string/last-index-of

(string/last-index-of [s :String needle :String] :(Option int))

byte offset of the last occurrence of needle in s.

sthe String to search (borrowed)
needlethe bytes to find (borrowed)

(some i) for the highest i where needle occurs, or (none). The empty needle is found at (string/len s).

(string/last-index-of (string/from-cstr "a/b/c") (string/from-cstr "/"))  ; => (some 3)

Since: markdown-library-plan S2

defn

string/-index-of-byte-loop

(string/-index-of-byte-loop [s :String b :int i :int n :int] :(Option int))

internal: first i in [i, n) holding byte b.

defn

string/index-of-char-from

(string/index-of-char-from [s :String c :Char start :int] :(Option int))

byte offset of the first c at or after start.

Compares single bytes, so c should be ASCII (see string/byte-is?). A negative start searches from 0.

sthe String to search (borrowed)
cthe character to find
startthe first byte offset to look at

(some i) for the lowest i >= start holding c, or (none).

(string/index-of-char-from (string/from-cstr "a]b]") #\] 2)  ; => (some 3)

Since: markdown-library-plan S2

defn

string/index-of-char

(string/index-of-char [s :String c :Char] :(Option int))

byte offset of the first c in s.

sthe String to search (borrowed)
cthe character to find (ASCII; see string/byte-is?)

(some i) for the lowest i holding c, or (none).

(string/index-of-char (string/from-cstr "[link](url)") #\])  ; => (some 5)

Since: markdown-library-plan S2

defn

string/-span-loop

(string/-span-loop [s :String pred :(fn [Char] bool) i :int n :int] :int)

internal: first i in [i, n) whose byte fails pred, else n.

defn

string/span-while

(string/span-while [s :String start :int pred :(fn [Char] bool)] :int)

the index where a run of bytes satisfying pred ends.

Scans from start while pred holds and returns the first index where it fails, or (string/len s) when it holds to the end. The char.tur predicates plug straight in: indentation width, the end of a name, a run of digits. pred sees each byte as a Char, so a multi-byte UTF-8 character is several calls. start is clamped into [0, (string/len s)].

sthe String to scan (borrowed)
startthe byte offset to start at
predthe test each byte must pass to continue the run

The end of the run: an index in [start, (string/len s)].

(string/span-while (string/from-cstr "   - item") 0 space?)  ; => 3

Since: markdown-library-plan S2

defn

string/-run-loop

(string/-run-loop [s :String b :int i :int n :int] :int)

internal: first i in [i, n) not holding byte b, else n.

defn

string/run-length

(string/run-length [s :String start :int c :Char] :int)

how many c in a row start at start.

Counts a fence (three or more backticks), an ATX heading's #s, a thematic break's dashes. Zero when start is out of range or the byte there is not c.

sthe String to scan (borrowed)
startthe byte offset the run starts at
cthe character the run is made of (ASCII)

The run's length in bytes, 0 or more.

(string/run-length (string/from-cstr "## Title") 0 #\#)  ; => 2

Since: markdown-library-plan S2

defn

string/concat

(string/concat [a :String b :String] :String)

concatenate two Strings into a fresh String.

Since: v2

defn

string/substring

(string/substring [s :String start :int len :int] :String)

fresh String of len bytes starting at start (clamped).

Out-of-range start/len are clamped to the String's bounds rather than erroring, so a substring past the end yields the empty String.

Since: v2

defn

string/to-upper

(string/to-upper [s :String] :String)

ASCII-uppercased copy.

Since: v2

defn

string/to-lower

(string/to-lower [s :String] :String)

ASCII-lowercased copy.

Since: v2

defn

string/trim

(string/trim [s :String] :String)

copy with ASCII leading/trailing whitespace removed.

Since: v2

defn

builder/new

(builder/new :StringBuilder)

a fresh empty StringBuilder (mutable, growable byte buffer).

Since: v2

defn

builder/push-cstr!

(builder/push-cstr! [b :StringBuilder s :cstr] :void)

append a cstr's bytes to the builder.

Since: v2

defn

builder/push-string!

(builder/push-string! [b :StringBuilder s :String] :void)

append a String's bytes to the builder.

Since: v2

defn

builder/push-byte!

(builder/push-byte! [b :StringBuilder c :int] :void)

append a single byte (0..255) to the builder.

Since: v2

defn

builder/push-char!

(builder/push-char! [b :StringBuilder c :Char] :void)

append one character (a Char, 0..255) to the builder.

bthe builder to append to
cthe character to append
(let [b (builder/new)]
  (do (builder/push-char! b #\h)
      (builder/push-char! b #\i)
      (builder/finish b)))  ; => String "hi"

Since: parsec-guide-plan P1

defn

builder/push-int!

(builder/push-int! [b :StringBuilder v :int] :void)

append the decimal digits of an int to the builder.

Writes the digits straight into the builder, with a leading - when v is negative, so there is no temporary String to release, unlike pushing (int->string v).

bthe builder to append to
vthe number to write
(let [b (builder/new)]
  (do (builder/push-int! b -42)
      (string/to-cstr (builder/finish b))))  ; => "-42"

Since: markdown-library-plan S5

defn

builder/push-repeat!

(builder/push-repeat! [b :StringBuilder c :Char n :int] :void)

append n copies of the character c to the builder.

Indentation, a rule of dashes, the padding of a column. Nothing is appended when n is 0 or less. c is one byte, so it should be ASCII.

bthe builder to append to
cthe character to repeat
nhow many copies
(let [b (builder/new)]
  (do (builder/push-repeat! b #\- 3)
      (string/to-cstr (builder/finish b))))  ; => "---"

Since: markdown-library-plan S5

defn

char->string

(char->string [c :Char] :String)

a fresh one-character String holding c.

cthe character (0..255)

A new owned String of length 1.

(string/to-cstr (char->string #\A))  ; => "A"

Since: parsec-guide-plan P1

defn

builder/len

(builder/len [b :StringBuilder] :int)

number of bytes accumulated so far.

Since: v2

defn

builder/finish

(builder/finish [b :StringBuilder] :String)

freeze the accumulated bytes into an immutable String.

Consumes the builder (frees it); do not use the builder afterward.

(let [b (builder/new)]
  (do (builder/push-cstr! b "a")
      (builder/push-cstr! b "b")
      (builder/finish b)))  ; => String "ab"

Since: v2

defn

string/-new-vec

(string/-new-vec :(Vec String))

internal: an empty (Vec String) (a let-bound vec-new is not inferred).

defn

string/-copy-range

(string/-copy-range [out :(Vec String) s :String start :int end :int] :void)

internal: push a fresh String of s's bytes [start, end) onto out.

defn

string/-split-loop

(string/-split-loop [s :String sep :String out :(Vec String) start :int] :(Vec String))

internal: split s on sep from start into out.

defn

string/split

(string/split [s :String sep :String] :(Vec String))

split s at each occurrence of sep.

The parts between separators, in order, including empty ones: "a,,b," split on "," is "a", "", "b", "". A string with no sep gives one part, a copy of itself; the empty string gives one empty part. An empty sep also gives one part, the whole string, since it would match everywhere.

sthe String to split (borrowed)
septhe separator (borrowed)

A fresh (Vec String) of fresh owned parts, at least one. Free it with string/release-all.

(vec-len (string/split (string/from-cstr "a, b, c") (string/from-cstr ", ")))  ; => 3

Since: markdown-library-plan S3

defn

string/-split-char-loop

(string/-split-char-loop [s :String c :Char out :(Vec String) start :int] :(Vec String))

internal: split s on byte b from start into out.

defn

string/split-char

(string/split-char [s :String c :Char] :(Vec String))

split s at each occurrence of the character c.

string/split with a one-byte separator, so c should be ASCII. Empty parts are kept: "|a||" split on #\| is "", "a", "", "".

sthe String to split (borrowed)
cthe separator character

A fresh (Vec String) of fresh owned parts, at least one. Free it with string/release-all.

(vec-len (string/split-char (string/from-cstr "| a | b |") #\|))  ; => 4

Since: markdown-library-plan S3

defn

string/-lines-loop

(string/-lines-loop [s :String out :(Vec String) start :int i :int n :int] :(Vec String))

internal: push s's lines from start into out, scanning at i.

defn

string/lines

(string/lines [s :String] :(Vec String))

split s into lines, without their line endings.

A line ends at LF, CRLF or CR, the three endings CommonMark recognises. A final line ending does not start another line, so "a\nb\n" is two lines, "a\n\n" is "a" and "", and the empty string has no lines.

sthe String to split (borrowed)

A fresh (Vec String) of fresh owned lines, possibly empty. Free it with string/release-all.

(vec-len (string/lines (string/from-cstr "one\r\ntwo\n")))  ; => 2

Since: markdown-library-plan S3

defn

string/-join-loop

(string/-join-loop [parts :(Vec String) sep :String b :StringBuilder i :int n :int] :void)

internal: push parts [i, n) onto b, sep between them.

defn

string/join

(string/join [parts :(Vec String) sep :String] :String)

concatenate parts with sep between each pair.

Borrows the parts and sep: none is released. No parts give the empty String. The inverse of string/split: joining what split returned with the same separator gives the original string back.

partsthe Strings to join, in order (borrowed)
septhe separator to put between them (borrowed)

A fresh owned String.

(let [v (string/split-char (string/from-cstr "a b c") #\space)]
  (string/to-cstr (string/join v (string/from-cstr "-"))))  ; => "a-b-c"

Since: markdown-library-plan S3

defn

string/-release-loop

(string/-release-loop [v :(Vec String) i :int n :int] :void)

internal: release v's elements [i, n).

defn

string/release-all

(string/release-all [v :(Vec String)] :void)

release every String in v, then free v itself.

The one call that frees what string/split, string/split-char and string/lines return. A Vec does not own its elements, so vec-free alone would leak every String in it. Do not use v, or any String taken out of it without string/retain, afterwards.

va (Vec String) whose elements this call owns
(string/release-all (string/lines (string/from-cstr "a\nb")))

Since: markdown-library-plan S3

defn

string/-trim-end-loop

(string/-trim-end-loop [s :String lo :int i :int] :int)

internal: the index past the last non-space byte in [lo, i).

defn

string/trim-start

(string/trim-start [s :String] :String)

copy with the leading ASCII whitespace removed.

sthe String to trim (borrowed)

A fresh owned String: s from its first non-whitespace byte on.

(string/to-cstr (string/trim-start (string/from-cstr "  - item ")))  ; => "- item "

Since: markdown-library-plan S4

defn

string/trim-end

(string/trim-end [s :String] :String)

copy with the trailing ASCII whitespace removed.

sthe String to trim (borrowed)

A fresh owned String: s up to and including its last non-whitespace byte.

(string/to-cstr (string/trim-end (string/from-cstr " # Title \t")))  ; => " # Title"

Since: markdown-library-plan S4

defn

string/-push-range!

(string/-push-range! [b :StringBuilder s :String i :int end :int] :void)

internal: append s's bytes [i, end) to b.

defn

string/-replace-loop

(string/-replace-loop [s :String from :String to :String b :StringBuilder start :int] :void)

internal: copy s from start into b, with to in place of each from.

defn

string/replace-all

(string/replace-all [s :String from :String to :String] :String)

copy of s with every occurrence of from replaced by to.

A literal replace: from is matched byte for byte, left to right, and the scan resumes after each match, so occurrences never overlap and to is never searched. An empty from matches nothing, so s comes back as a copy, the same rule string/split has for an empty separator. For a pattern, use re/replace-all.

sthe String to copy (borrowed)
fromthe text to replace (borrowed)
tothe text to put in its place (borrowed; may be empty)

A fresh owned String.

(string/to-cstr (string/replace-all (string/from-cstr "a&b&c")
                                    (string/from-cstr "&")
                                    (string/from-cstr "&amp;")))  ; => "a&amp;b&amp;c"

Since: markdown-library-plan S4

defn

string/-repeat-loop

(string/-repeat-loop [b :StringBuilder s :String n :int] :void)

internal: append s to b n times.

defn

string/repeat

(string/repeat [s :String n :int] :String)

s written n times in a row.

sthe String to repeat (borrowed)
nhow many copies; 0 or less gives the empty String

A fresh owned String of (* n (string/len s)) bytes.

(string/to-cstr (string/repeat (string/from-cstr "ab") 3))  ; => "ababab"

Since: markdown-library-plan S4

defn

string/pad-start

(string/pad-start [s :String width :int c :Char] :String)

s with copies of c in front, to make it width bytes.

Lengths are in bytes, as everywhere in String, so c should be ASCII. A String already width bytes or longer comes back as an unchanged copy; it is never cut.

sthe String to pad (borrowed)
widththe length to pad to
cthe padding character

A fresh owned String of (max width (string/len s)) bytes.

(string/to-cstr (string/pad-start (int->string 42) 5 #\0))  ; => "00042"

Since: markdown-library-plan S4

defn

string/pad-end

(string/pad-end [s :String width :int c :Char] :String)

s with copies of c after it, to make it width bytes.

string/pad-start, padding on the right: a table cell or a column of names. A String already width bytes or longer comes back as a copy.

sthe String to pad (borrowed)
widththe length to pad to
cthe padding character (ASCII)

A fresh owned String of (max width (string/len s)) bytes.

(string/to-cstr (string/pad-end (string/from-cstr "ab") 4 #\.))  ; => "ab.."

Since: markdown-library-plan S4

defn

string/-parse-digits

(string/-parse-digits [s :String i :int n :int acc :int] :(Option int))

internal: s's digits [i, n) folded into acc as a negative int, or (none).

defn

string/-signed-int

(string/-signed-int [neg :bool digits :(Option int)] :(Option int))

internal: the parsed value from the negated digits, or (none).

defn

string/parse-int

(string/parse-int [s :String] :(Option int))

the decimal integer s spells, or (none).

The whole of s must be the number: an optional + or -, then one or more digits 0-9, and nothing else -- no spaces, no underscores, no 0x. Leading zeros are fine. A number outside the 64-bit int range is (none), never a wrapped or clamped value. str->int-checked, by contrast, takes a cstr, skips leading spaces and clamps on overflow.

sthe String to parse (borrowed)

(some n) when s is exactly a decimal integer n, else (none).

(string/parse-int (string/from-cstr "-042"))  ; => (some -42)
(string/parse-int (string/from-cstr "12."))   ; => (none)

Since: markdown-library-plan S4

defclass

BuilderPush

(defclass BuilderPush [a])

types builder/push! can append; builder/-push-into! appends x to b.

The value comes first because a class method dispatches on its first argument; builder/push! puts the builder first, like the other pushes.

(builder/-push-into! [x :a b :StringBuilder] :void)

StringSlice, cstr, String, Char, int, bool

definstance

BuilderPush[cstr]

(definstance BuilderPush [cstr])

the bytes up to the NUL.

definstance

BuilderPush[String]

(definstance BuilderPush [String])

the String's bytes; it is borrowed, not released.

definstance

BuilderPush[Char]

(definstance BuilderPush [Char])

the one character.

definstance

BuilderPush[int]

(definstance BuilderPush [int])

the decimal digits, as builder/push-int!.

definstance

BuilderPush[bool]

(definstance BuilderPush [bool])

true or false.

defn

builder/push!

(builder/push! [A])

append any BuilderPush value to the builder.

One name for every push: a cstr, String or StringSlice appends its bytes, a Char its character, an int its decimal digits and a bool true or false. The value is borrowed, so a String passed in is not released. string/of is the usual way to reach this.

bthe builder to append to
xthe value to append
(let [b (builder/new)]
  (do (builder/push! b "n=")
      (builder/push! b 42)
      (string/to-cstr (builder/finish b))))  ; => "n=42"

Since: markdown-library-plan S5

defmacro

string/-push-all__

(string/-push-all__ [b & ^syntax xs])

internal: (builder/push! b x) for each x, in order.

defmacro

string/of

(string/of [& ^syntax xs])

one fresh String made of all its arguments, in order.

Each argument is any BuilderPush value: a cstr, String, StringSlice, Char, int or bool. It expands to one builder, a builder/push! per argument and builder/finish, so nothing in between is allocated, and the one String it returns is the only thing to release. Arguments are borrowed and evaluated left to right. A call that returns a fresh String, such as (int->string n), is borrowed too and would leak; pass n itself.

xsthe parts, zero or more

A fresh owned String; (string/of) is the empty String.

(string/to-cstr (string/of "x=" 3 #\, "ok=" true))  ; => "x=3,ok=true"

Since: markdown-library-plan S5

definstance

Eq[String]

(definstance Eq [String])

content equality.

definstance

Ord[String]

(definstance Ord [String])

lexicographic byte ordering.

definstance

Hash[String]

(definstance Hash [String])

content hash over the byte range.

definstance

Clone[String]

(definstance Clone [String])

O(1) retain (refcount++), returning a second owning handle.

definstance

Drop[String]

(definstance Drop [String])

release one owning handle (refcount--), freeing at zero.

Paired with Clone [String] (retain), this lets the closure drop-glue treat a captured String as a shared refcounted owner: retained when captured, released when the capturing env dies -- so an owned String captured into an escaping closure (e.g. httpd mw-cors config strings) is reclaimed instead of leaking.

Since: v2 (Model R)

definstance

MapKey[String]

(definstance MapKey [String])

owned key: the map copies the bytes into a boxed key it owns and frees (mk-owned? = 1), so a String key never dangles. mk-cmp is the size-aware content comparator over boxed keys.

Internal definitions