lua_std/extended.rs
1//! Items from `extended.lua` (cargo feature `extended`).
2
3use crate::{Repeatable, any, boolean, function, number, option, string, table};
4
5/// # Extended library — feature `extended`
6///
7/// Functions from `extended.lua`, inspired by Rust.
8/// They are not part of standard Lua; `require("extended")` installs
9/// them into the string library, so they also work in method form.
10impl string {
11 /// Splits a string into a sequence of substrings.
12 ///
13 /// *Inspired by Rust's [`str::split`].*
14 ///
15 /// # Parameters
16 ///
17 /// - **`sep`**: the separator, taken as *literal text* (not a
18 /// pattern). When absent, splits on runs of whitespace.
19 /// Must not be empty.
20 ///
21 /// # Return value
22 ///
23 /// A new sequence with the pieces. With an explicit separator,
24 /// empty fields are kept.
25 ///
26 /// # Examples
27 ///
28 /// ```lua
29 /// print(inspect(("a,b,c"):split(","))) --> { "a", "b", "c" }
30 /// print(inspect(("a,,b"):split(","))) --> { "a", "", "b" }
31 /// print(inspect((" one two "):split())) --> { "one", "two" }
32 /// print(inspect(("a.b"):split("."))) --> { "a", "b" } (literal dot)
33 /// ```
34 pub fn split(&self, sep: option<string>) -> table {
35 todo!()
36 }
37
38 /// Removes leading and trailing whitespace.
39 ///
40 /// *Inspired by Rust's [`str::trim`].*
41 ///
42 /// # Examples
43 ///
44 /// ```lua
45 /// print((" hi \n"):trim()) --> hi
46 /// print((" "):trim()) --> (empty string)
47 /// ```
48 pub fn trim(&self) -> string {
49 todo!()
50 }
51
52 /// Tests whether the string starts with a prefix.
53 ///
54 /// *Inspired by Rust's [`str::starts_with`].*
55 ///
56 /// # Examples
57 ///
58 /// ```lua
59 /// print(("hello"):startswith("he")) --> true
60 /// print(("hello"):startswith("lo")) --> false
61 /// print(("hello"):startswith("")) --> true
62 /// ```
63 ///
64 /// # See also
65 ///
66 /// [`endswith`](string::endswith)
67 pub fn startswith(&self, prefix: string) -> boolean {
68 todo!()
69 }
70
71 /// Tests whether the string ends with a suffix.
72 ///
73 /// *Inspired by Rust's [`str::ends_with`].*
74 ///
75 /// # Examples
76 ///
77 /// ```lua
78 /// print(("hello"):endswith("lo")) --> true
79 /// print(("hello"):endswith("he")) --> false
80 /// ```
81 ///
82 /// # See also
83 ///
84 /// [`startswith`](string::startswith)
85 pub fn endswith(&self, suffix: string) -> boolean {
86 todo!()
87 }
88
89 /// Tests whether the string contains a substring.
90 ///
91 /// The needle is literal text: `("a.b"):contains(".")` asks about a
92 /// real dot, with none of `find`'s pattern-escaping footguns.
93 ///
94 /// *Inspired by Rust's [`str::contains`].*
95 ///
96 /// # Examples
97 ///
98 /// ```lua
99 /// print(("hello"):contains("ell")) --> true
100 /// print(("a.b"):contains(".")) --> true
101 /// print(("hello"):contains("xyz")) --> false
102 /// ```
103 pub fn contains(&self, sub: string) -> boolean {
104 todo!()
105 }
106
107 /// Replaces occurrences of a literal substring.
108 ///
109 /// *Inspired by Rust's [`str::replace`] & [`str::replacen`]*.
110 ///
111 /// # Parameters
112 ///
113 /// - **`old`**: the substring to find — literal, never a pattern.
114 /// - **`new`**: the replacement — also literal; `%1` means two
115 /// characters, not a capture.
116 /// - **`n`**: the maximum number of replacements (default:
117 /// unlimited).
118 ///
119 /// # Examples
120 ///
121 /// ```lua
122 /// print(("a.b.c"):replace(".", "-")) --> a-b-c
123 /// print(("a.b.c"):replace(".", "-", 1)) --> a-b.c
124 /// print(("aaa"):replace("a", "%0")) --> %0%0%0
125 /// ```
126 pub fn replace(&self, old: string, new: string, n: option<number>) -> string {
127 todo!()
128 }
129
130 /// Counts non-overlapping occurrences of a substring.
131 ///
132 /// # Examples
133 ///
134 /// ```lua
135 /// print(("banana"):count("an")) --> 2
136 /// print(("aaaa"):count("aa")) --> 2 (non-overlapping)
137 /// ```
138 pub fn count(&self, sub: string) -> number {
139 todo!()
140 }
141
142 /// Pads the string on the left to a given length.
143 ///
144 /// # Parameters
145 ///
146 /// - **`len`**: the target length. Longer strings are returned
147 /// unchanged.
148 /// - **`char`**: the fill character (default `" "`).
149 ///
150 /// # Examples
151 ///
152 /// ```lua
153 /// print(("7"):padleft(3)) --> 7
154 /// print(("7"):padleft(3, "0")) --> 007
155 /// ```
156 ///
157 /// # See also
158 ///
159 /// [`padright`](string::padright)
160 pub fn padleft(&self, len: number, char: option<string>) -> string {
161 todo!()
162 }
163
164 /// Pads the string on the right to a given length.
165 ///
166 /// # Examples
167 ///
168 /// ```lua
169 /// print(("7"):padright(3, ".")) --> 7..
170 /// ```
171 ///
172 /// # See also
173 ///
174 /// [`padleft`](string::padleft)
175 pub fn padright(&self, len: number, char: option<string>) -> string {
176 todo!()
177 }
178
179 /// Returns an iterator over the lines of the string.
180 ///
181 /// A trailing newline does not produce a final empty line, and a
182 /// trailing `\r` (Windows line endings) is stripped from each line.
183 ///
184 /// *Inspired by Rust's [`str::lines`].*
185 ///
186 /// # Examples
187 ///
188 /// ```lua
189 /// for line in ("one\ntwo\r\nthree\n"):lines() do
190 /// print(line) --> one / two / three
191 /// end
192 /// ```
193 pub fn lines(&self) -> function {
194 todo!()
195 }
196
197 /// Tests whether the string consists only of letters.
198 /// False for the empty string.
199 ///
200 /// *Inspired by Rust's [`char::is_alphabetic`].*
201 ///
202 /// # Examples
203 ///
204 /// ```lua
205 /// print(("abc"):is_alphabetic()) --> true
206 /// print(("ab1"):is_alphabetic()) --> false
207 /// print((""):is_alphabetic()) --> false
208 /// ```
209 pub fn is_alphabetic(&self) -> boolean {
210 todo!()
211 }
212
213 /// Tests whether the string consists only of decimal digits.
214 /// False for the empty string.
215 ///
216 /// *Inspired by Rust's [`char::is_numeric`].*
217 ///
218 /// # Examples
219 ///
220 /// ```lua
221 /// print(("123"):is_numerical()) --> true
222 /// print(("12.3"):is_numerical()) --> false (the dot is not a digit)
223 /// ```
224 pub fn is_numerical(&self) -> boolean {
225 todo!()
226 }
227
228 /// Tests whether the string consists only of letters and digits.
229 /// False for the empty string.
230 ///
231 /// *Inspired by Rust's [`char::is_alphanumeric`].*
232 ///
233 /// # Examples
234 ///
235 /// ```lua
236 /// print(("a1"):is_alphanumeric()) --> true
237 /// print(("a_1"):is_alphanumeric()) --> false
238 /// ```
239 pub fn is_alphanumeric(&self) -> boolean {
240 todo!()
241 }
242
243 /// Tests whether the string has at least one letter and no
244 /// lowercase ones.
245 ///
246 /// *Inspired by Rust's [`char::is_uppercase`].*
247 ///
248 /// # Examples
249 ///
250 /// ```lua
251 /// print(("ABC1"):is_upper()) --> true
252 /// print(("AbC"):is_upper()) --> false
253 /// print(("123"):is_upper()) --> false (no letters at all)
254 /// ```
255 pub fn is_upper(&self) -> boolean {
256 todo!()
257 }
258
259 /// Tests whether the string has at least one letter and no
260 /// uppercase ones.
261 ///
262 /// *Inspired by Rust's [`char::is_lowercase`].*
263 ///
264 /// # Examples
265 ///
266 /// ```lua
267 /// print(("abc1"):is_lower()) --> true
268 /// print(("aBc"):is_lower()) --> false
269 /// ```
270 pub fn is_lower(&self) -> boolean {
271 todo!()
272 }
273}
274
275/// # Extended library — feature `extended`
276///
277/// Sequence functions from `extended.lua`, inspired by Rust. All of them return *new* tables — only the standard
278/// library's `sort`, `insert` and `remove` mutate. Signatures with
279/// `self` take the table as their first argument:
280/// `table.map(t, f)`.
281impl table {
282 /// Transforms every element of a sequence.
283 ///
284 /// *Inspired by Rust's [`Iterator::map`].*
285 ///
286 /// # Parameters
287 ///
288 /// - **`f`**: called as `f(value, index)`; its result becomes the
289 /// element of the new sequence.
290 ///
291 /// # Examples
292 ///
293 /// ```lua
294 /// print(inspect(table.map({1, 2, 3}, function(v) return v * 2 end)))
295 /// --> { 2, 4, 6 }
296 /// ```
297 ///
298 /// # See also
299 ///
300 /// [`filter`](table::filter), [`fold`](table::fold)
301 pub fn map(&self, f: function) -> table {
302 todo!()
303 }
304
305 /// Keeps the elements of a sequence that satisfy a predicate.
306 ///
307 /// *Inspired by Rust's [`Iterator::filter`].*
308 ///
309 /// # Examples
310 ///
311 /// ```lua
312 /// print(inspect(table.filter({1, 2, 3, 4}, function(v)
313 /// return v % 2 == 0
314 /// end)))
315 /// --> { 2, 4 }
316 /// ```
317 ///
318 /// # See also
319 ///
320 /// [`map`](table::map), [`find`](table::find)
321 pub fn filter(&self, pred: function) -> table {
322 todo!()
323 }
324
325 /// Folds a sequence into a single value.
326 ///
327 /// *Inspired by Rust's [`Iterator::fold`].*
328 ///
329 /// # Parameters
330 ///
331 /// - **`f`**: called as `f(accumulator, value)`.
332 /// - **`init`**: the initial accumulator. When absent, folding
333 /// starts from the first element.
334 ///
335 /// # Examples
336 ///
337 /// ```lua
338 /// print(table.fold({1, 2, 3, 4}, function(a, b) return a + b end))
339 /// --> 10
340 /// print(table.fold({1, 2, 3}, function(a, b) return a + b end, 100))
341 /// --> 106
342 /// ```
343 ///
344 /// # See also
345 ///
346 /// [`sum`](table::sum), [`map`](table::map)
347 pub fn fold(&self, f: function, init: option<any>) -> any {
348 todo!()
349 }
350
351 /// Finds the first element satisfying a predicate.
352 ///
353 /// *Inspired by Rust's [`Iterator::find`].*
354 ///
355 /// # Return value
356 ///
357 /// The first matching value and its index, or `nil` when nothing
358 /// matches.
359 ///
360 /// # Examples
361 ///
362 /// ```lua
363 /// print(table.find({5, 6, 7}, function(v) return v > 5 end))
364 /// --> 6 2
365 /// ```
366 ///
367 /// # See also
368 ///
369 /// [`contains`](table::contains), [`filter`](table::filter)
370 pub fn find(&self, pred: function) -> option<(any, number)> {
371 todo!()
372 }
373
374 /// Tests whether a sequence contains a value (compared with `==`).
375 ///
376 /// *Inspired by Rust's [`std::collections::HashSet::contains`].*
377 ///
378 /// # Examples
379 ///
380 /// ```lua
381 /// print(table.contains({1, 2, 3}, 2)) --> true
382 /// print(table.contains({1, 2, 3}, 9)) --> false
383 /// ```
384 pub fn contains(&self, value: any) -> boolean {
385 todo!()
386 }
387
388 /// Returns the keys of a table as a new sequence.
389 /// The order is unspecified, as with
390 /// [`pairs`](crate::pairs).
391 ///
392 /// *Inspired by Rust's [`std::collections::HashMap::keys`].*
393 ///
394 /// # Examples
395 ///
396 /// ```lua
397 /// local ks = table.keys({ a = 1, b = 2 })
398 /// table.sort(ks)
399 /// print(inspect(ks)) --> { "a", "b" }
400 /// ```
401 ///
402 /// # See also
403 ///
404 /// [`values`](table::values)
405 pub fn keys(&self) -> table {
406 todo!()
407 }
408
409 /// Returns the values of a table as a new sequence.
410 /// The order is unspecified.
411 ///
412 /// *Inspired by Rust's [`std::collections::HashMap::values`].*
413 ///
414 /// # Examples
415 ///
416 /// ```lua
417 /// local vs = table.values({ a = 1, b = 2 })
418 /// table.sort(vs)
419 /// print(inspect(vs)) --> { 1, 2 }
420 /// ```
421 ///
422 /// # See also
423 ///
424 /// [`keys`](table::keys)
425 pub fn values(&self) -> table {
426 todo!()
427 }
428
429 /// Returns a new sequence with the elements in reverse order.
430 ///
431 /// *Inspired by Rust's [`slice::reverse`].*
432 ///
433 /// # Examples
434 ///
435 /// ```lua
436 /// print(inspect(table.reverse({1, 2, 3}))) --> { 3, 2, 1 }
437 /// ```
438 pub fn reverse(&self) -> table {
439 todo!()
440 }
441
442 /// Copies a contiguous range into a new sequence.
443 /// With Lua index
444 /// conventions: 1-based, inclusive, negative indices count from
445 /// the end (as in [`string::sub`]).
446 ///
447 /// # Examples
448 ///
449 /// ```lua
450 /// print(inspect(table.slice({1, 2, 3, 4, 5}, 2, 4))) --> { 2, 3, 4 }
451 /// print(inspect(table.slice({1, 2, 3, 4, 5}, -2))) --> { 4, 5 }
452 /// ```
453 pub fn slice(&self, i: option<number>, j: option<number>) -> table {
454 todo!()
455 }
456
457 /// Pairs two sequences element by element.
458 ///
459 /// *Inspired by Rust's [`Iterator::zip`].*
460 ///
461 /// # Return value
462 ///
463 /// A new sequence of two-element tables `{a[i], b[i]}`, stopping at
464 /// the end of the shorter input.
465 ///
466 /// # Examples
467 ///
468 /// ```lua
469 /// print(inspect(table.zip({1, 2, 3}, {"a", "b"})))
470 /// --> { { 1, "a" }, { 2, "b" } }
471 /// ```
472 pub fn zip(a: table, b: table) -> table {
473 todo!()
474 }
475
476 /// Tests whether any element satisfies a predicate.
477 ///
478 /// Without a predicate, tests Lua truthiness.
479 /// The empty sequence yields false.
480 ///
481 /// Inspired by Rust's [`Iterator::any`].
482 ///
483 /// # Examples
484 ///
485 /// ```lua
486 /// print(table.any({false, nil, 3})) --> true
487 /// print(table.any({1, 2}, function(v) return v > 1 end)) --> true
488 /// print(table.any({})) --> false
489 /// ```
490 ///
491 /// # See also
492 ///
493 /// [`all`](table::all)
494 pub fn any(&self, pred: option<function>) -> boolean {
495 todo!()
496 }
497
498 /// Tests whether every element satisfies a predicate.
499 /// Without a predicate, tests Lua truthiness.
500 /// The empty sequence yields true (vacuous truth).
501 ///
502 /// *Inspired by Rust's [`Iterator::all`].*
503 ///
504 /// # Examples
505 ///
506 /// ```lua
507 /// print(table.all({1, "x", true})) --> true
508 /// print(table.all({2, 3}, function(v) return v > 2 end)) --> false
509 /// print(table.all({})) --> true
510 /// ```
511 ///
512 /// # See also
513 ///
514 /// [`any`](table::any)
515 pub fn all(&self, pred: option<function>) -> boolean {
516 todo!()
517 }
518
519 /// Copies a table.
520 ///
521 /// # Parameters
522 ///
523 /// - **`deep`**: when true, copies nested tables recursively —
524 /// including table keys — and follows cycles safely.
525 ///
526 /// # Return value
527 ///
528 /// A new table. The metatable *reference* is kept in both modes
529 /// (the metatable itself is never copied).
530 ///
531 /// # Examples
532 ///
533 /// ```lua
534 /// local src = {1, {2}}
535 /// local sh = table.copy(src)
536 /// print(sh[2] == src[2]) --> true (shallow: shared inner table)
537 /// local dp = table.copy(src, true)
538 /// print(dp[2] == src[2]) --> false (deep: its own inner table)
539 /// ```
540 pub fn copy(&self, deep: option<boolean>) -> table {
541 todo!()
542 }
543
544 /// Removes duplicate values, keeping first occurrences in order.
545 ///
546 /// # Examples
547 ///
548 /// ```lua
549 /// print(inspect(table.uniq({1, 2, 1, 3, 2}))) --> { 1, 2, 3 }
550 /// ```
551 pub fn uniq(&self) -> table {
552 todo!()
553 }
554
555 /// Sums a sequence of numbers.
556 /// The empty sequence sums to 0.
557 ///
558 /// *Inspired by Rust's [`Iterator::sum`].*
559 ///
560 /// # Examples
561 ///
562 /// ```lua
563 /// print(table.sum({1, 2, 3.5})) --> 6.5
564 /// print(table.sum({})) --> 0
565 /// ```
566 ///
567 /// # See also
568 ///
569 /// [`fold`](table::fold)
570 pub fn sum(&self) -> number {
571 todo!()
572 }
573}
574
575/// Renders any value as a human-readable string. **Extended library —
576/// feature `extended`.**
577/// In the spirit of the widely used `inspect.lua`.
578///
579/// Tables are rendered recursively with indentation and a
580/// deterministic key order; cycles are detected and shown as
581/// `<cycle ...>`; strings are quoted; a table with a `__tostring`
582/// metamethod is rendered through it.
583///
584/// # Examples
585///
586/// ```lua
587/// print(inspect({1, "two", nested = { ok = true }}))
588/// --> {
589/// --> 1,
590/// --> "two",
591/// --> nested = {
592/// --> ok = true
593/// --> }
594/// --> }
595/// local t = {}; t.me = t
596/// print(inspect(t)) --> { me = <cycle table: 0x...> }
597/// ```
598///
599/// # See also
600///
601/// [`tostring()`](crate::tostring()), [`print()`](crate::print())
602pub fn inspect(value: any) -> string {
603 todo!()
604}
605
606// Quiet unused-import warnings for combinations not used above.
607#[allow(unused_imports)]
608use Repeatable as _;