Skip to main content

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 _;