Right now, we write code like
```rust
match q_once(q, inputs)?.into_tuple()? {
Some(vs) => match (vs.len(), vs.get(0), vs.get(1)) {
(2, &Some(Binding::Scalar(TypedValue::Long(a))), &Some(Binding::Scalar(TypedValue::Instant(ref b)))) => Some((a, b.clone())),
_ => panic!(),
},
None => None,
}
```
to length-check tuples coming out of the database. It can also lead
to a lot of cloning because references are the easiest thing to hand.
This commit allows to write code like
```rust
match q_once(q, inputs)?.into_tuple()? {
Some((Binding::Scalar(TypedValue::Long(a)), Binding::Scalar(TypedValue::Instant(b)))) => Some((a, b)),
Some(_) => panic!(),
None => None,
}
```
which is generally much easier to reason about.
Perhaps we actually want to subdivide the top-level namespace so that
there is a `mentat::time` module, but I'd prefer to make part of the
process of fixing the public API as we get ready to christen version
1.0.
I think this is just oversight. Generally, we should anticipate what
our consumers need to do to interact with Mentat, and producing milli-
and micro-second timestamps is part of that need.
These are functions on `TermBuilder` itself to prevent mixing mutable
and immutable references in the most natural style. That is,
```
builder.add(e, a, builder.lookup_ref(...))
```
fails because `add` borrows `builder` mutably and `lookup_ref` borrows
`builder` immutably. There's nothing here that requires a specific
builder (since we're not interning lookup refs on the builder, like we
are tempids) so we don't need an instance.
There are a few tricky details to call out here. The first is the
`TransactableValueMarker` trait. This is strictly a marker (like
`Sized`, for example) to give some control over what types can be used
as value types in `Entity` instances. This expression is needed due
to the network of `Into` and `From` relations between the parts of
valid `Entity` instances. This allows to drop the `IntoThing`
work-around trait and use the established patterns. (Observe that
`KnownEntid` makes this a little harder, due to the cross-crate
consistency restrictions.)
The second is that we can get rid `{add,retract}_kw`, since the
network of relations expresses the coercions directly.
The third is that this commit doesn't change the name `TermBuilder`,
even though it is now building `Entity` instances. This is because
there's _already_ an `EntityBuilder` which fixes the `EntityPlace`.
It's not clear whether the existing entity building interface should
be removed or whether both should be renamed. That can be follow-up.
This is all part of moving the entity builder away from building term
instances and toward building entity instances. One of the nice
things that the existing term interface does is allow consumers to use
lightweight reference counted tempid handles; I don't want to lose
that, so we'll build it into the entity data structures directly.
We haven't observed performance issues using `Arc` instead of `Rc`,
and we want to be able to include things that are interned (including,
soon, `TempId` instances) in errors coming out of the
transactor. (And `Rc` isn't `Sync`, so it can't be included in errors
directly.)
It's not great to keep lifting functionality higher and higher up the
crate hierarchy, but we really do want to intern while we parse.
Eventually, I expect that we will split the `edn` crate into `types`
and `parsing`, and the `types` crate can depend on a more efficient
interning dependency.
With the transition toward parsing with `rust-peg` and away from
`combine`, we're not using some of the many helpers we built to
support our unusual `combine` usage. They can just go!
* Fix broken API doc links
Create symlink for latest to point to v0.7.
Group APIs by top version number rather than individual
* Update swift and android version numbers to match Mentats
* Update documentation
* Update top level .gitignore to ignore docs site & metatdata
* Add README to help with building documentation site
* Address review comments @ncalexan
In the language of
868273409c/book/src/error-errorkind.md
Mentat is a mid-level API, not an application, and therefore we should
prefer our own error types. Writing an initial consumer of Mentat (a
Rust logins API targeting Mozilla Lockbox), I have found this to be
true: my consumer wants to consume concrete Mentat error types.
This doesn't go "all the way" and convert all sub-crates to the
Error/ErrorKind, but it does go part of the way.
We're not exposing a uniform API with `mentat::Result` yet, meaning
that early consumers (e.g., the logins work for Mozilla Lockbox) need
to wrap errors from all over the Mentat crate hierarchy.
I elected to keep Tolstoy using `failure::Error`, because Tolstoy
looks rather more like a high-level application (and will continue to
do so for a while) than a production-ready mid- or low-level API.
* Delete the (apparently unused) EntId
* Rename edn's Entid to EntidOrIdent to avoid confusion with the Entid that's actually an i64
* Fix travis beta bustage (This is actually unrelated to entids, but is a trivial fix nonetheless)
Steps to building docs locally:
1. Install Jekyll
2. cd docs
3. bundle exec jekyll serve --incremental
4. open local docs site at http://127.0.0.1:4000/
* basic Jekyll site
* Add docs to documentation site
* Update javadoc to allow for error free builds
* Remove docs for rust dependencies
* Better display examples, about and contributing documentation for Mentat
* Version docs
It's not possible to do meaningful clean-up (such as saving history)
if we use exit() to quit. Instead, each handled command returns a
boolean requesting exit. I elected not to allow ".exit" when
processing commands from the command line; it might be useful to
handle accept that. In general, though, REPLs that accept "-c
'commands'" on the command line exit after processing those commands,
so I'd rather think more deeply about that model than build in ".exit"
with our existing system.
I don't really understand why we were using `linefeed::Reader`
directly, but reading is not the full set of linefeed features we want
to access. I think the `linefeed::Interface` should be owned by the
`Repl`, not the `InputReader`, but it's a little awkward to share
access with that configuration, so I'm not going to lift the ownership
until I have a reason to.
I think the "--no-tty" argument might be useful for running inside
Emacs. Along the way, I made read_stdin() strip the trailing newline,
which agrees with InputReader::read_line().
What was happening is that ["[;", "]"] would get glued to "[; ]",
which of course can never complete.
It would be good to add tests of this, but the existing multi-line
`InputReader` makes that challenging and I don't want to invest the
time to improve it: I expect it to be overhauled as part of a
transition away from parsing with `combine` and toward parsing with
`rust-peg`.
This is neat, because currently at the FFI boundary we're primarily concerned
with verbalizing our errors. It doesn't matter what 'error' that's wrapped by
Result is then, as long as it can be displayed.
Once we're past the prototyping stage, it might be a good idea to formalize this.