I would like to suggest some changes to the stdlib::path API that would
make it cleaner to use. Currently it feels clunky and disjointed, and
common operations require many variable assignments or workarounds using
stdlib::strings.
The conceptual model of these functions treats a path::buffer as a stack
of path segments, and the file extension(s) of the final path segment as
a mini-stack too. In the case of path segments, this reflects filetree
traversal (i.e. pop() <=> cd ..). In the case of file extensions, it
just makes it simpler to manipulate them.
This stack model is already hinted at in the current API with functions
like add() and extension(), but I think explicitly committing to it is a
good idea.
Other changes include:
- removing functions that do allocs.
- making arguments variadic where sensible
- making most functions only take a *buffer not a (*buffer|str), for
consistency and simplicity of implementation. I'm not too bothered about
this point, though.
Below is the set of functions that I think should replace the current
API, annotated with additional changes and context.
m modified or renamed
+ added
- removed
Basic
=====
m init(str...) (buffer | errors::overflow)
reset(*buffer) void
m abs(*buffer) bool
string(*buffer) str
- allocate(*buffer) str [use strings::dup]
- join(str...) str [use path::init and strings::dup]
- set(*buffer, str...) [use path::init]
It makes more sense if the whole module uses no allocs, and the strings
module is used in the path module anyway already. set() could be kept if
stack space is a significant concern.
Path segment level
==================
m push(*buffer, str...) (str | errors::overflow)
+ pop(*buffer) (str | void)
m peek(*buffer) (str | void) [replaces old 'basename']
m dirname(*buffer) (str | void)
pop and peek should return void only when the path is empty or is the
root dir.
File extension level
====================
+ push_ext(*buffer, str...) (str | errors::overflow)
m pop_ext(*buffer) (str | void) [similar to old extension()]
+ peek_ext(*buffer) (str | void)
+ basename(*buffer) str [returns filename up to first '.']
the *_ext functions should not use a leading '.' before the extension.
This is so that filenames ending in '.' have extension "", and filenames
with no extension have extension `void`. This also makes it easier to
manipulate extensions using strings::{split, join}.
Iterators
=========
m iter(*buffer) iterator
+ riter(*buffer) iterator [reverse iter is just as common as forward]
next(*iterator) (str|void)
+ remaining(*iterator) str
Iterators should be (documented as) copyable to save their state