Skip to main content

Crate taglogwriter

Crate taglogwriter 

Source
Expand description

Writes tag SQLite logs through the C++ writer.

LogWriter is a safe wrapper over the C interface in host/libraries/tagcore-c/taglogwriter_c.h, which wraps the C++ SqliteTagLogWriter that tag-dwnld, tag-log-import and the Qt applications use. Each message crosses as its protobuf wire encoding, so the database is exactly the one the C++ tools write: one writer, one schema, and no log format interpreted on the Rust side.

The sequence follows a download:

use taglogwriter::{LogHeader, LogWriter};
let mut writer = LogWriter::create("tag.db3".as_ref(), &header.config, true)?;
writer.write_header(&header)?;
writer.begin_log()?;
let mut index = 0;
loop {
    // The writer says how far each page advances the download, and
    // where it ends: both depend on the tag type.
    let consumed = writer.write_log(&read_page(index))?;
    if consumed == 0 {
        break;
    }
    index += consumed;
}
writer.end_log()?;

§Linking

The crate links libtagcore_c, which CMake builds with -DBUILD_TAGCORE_C=ON, through tagcore-c-sys, whose build script finds it through TAGCORE_C_LIB_DIR and which the other wrappers over the library share, so a program may use them together. On macOS it links the static archive (tagcore_c_static), since each application is its own bundle, and the executable needs nothing at run time. On Linux and Windows it links the shared library, one copy of which serves every tool in the install directory, and a binary must find it at run time: on Linux its package’s build script sets an rpath from DEP_TAGCORE_C_LIB_DIR, which a direct dependent of tagcore-c-sys reads (see commandline-rs/build.rs); on Windows the DLL must sit beside the executable or on PATH. TAGCORE_C_LINK=dylib forces the shared library on macOS too.

§Safety model

All unsafe is in this file, and every call states why it is sound. Three rules carry the whole argument:

  • Ownership. A LogWriter owns exactly one C handle, never null, closed exactly once in Drop. Nothing else holds the pointer.
  • Borrowed buffers. Every pointer passed in (a path, an encoded message, an info string) points at Rust memory that lives until the call returns. The library copies what it keeps and holds no pointer after the call.
  • Returned strings. tlw_last_error() returns memory owned by the handle, valid only until the next call on it, so it is copied out at once, by the private LogWriter::last_error, which is why it is not public.

A handle may move between threads but must not be used from two at once: LogWriter is Send and not Sync, and every writing method takes &mut self.

§Maintaining

The declarations, imported here as ffi, are tagcore_c_sys::tlw (host/libraries/tagcore-c-sys/src/tlw.rs), written by hand from host/libraries/tagcore-c/taglogwriter_c.h; with a dozen functions, bindgen would cost more than it saves. When the header changes:

  1. Change the matching declaration in tlw.rs, and the safe method over it.
  2. If a function’s signature or meaning changed, the header raises TLW_ABI_VERSION; raise ffi::TLW_ABI_VERSION to match. LogWriter::create refuses a library whose version differs, so a stale library fails with a message instead of misbehaving.
  3. Keep ffi::TLW_CONFIG … TLW_STATE equal to the header’s tlw_header_kind values.

The messages themselves need no such care: both sides compile them from the same proto/ files (prost here, protoc for the library), and protobuf wire encoding is the contract between them. A field added to proto/ reaches the C++ writer once both are rebuilt.

The design, including how the library is built and why, is in host/libraries/tagcore-c/design/architecture.md.

Structs§

LogHeader
Everything a log records about the tag before its data: the C++ TagLogHeader.
LogWriter
One SQLite log being written by the C++ writer.
WriterError
Why a writer call failed: the C++ writer’s own message, or the interface’s (a message that did not parse, a version mismatch).

Functions§

set_debug
Sets how much the C++ writer logs to stderr: everything at DEBUG when enabled, errors only otherwise, as the C++ tools’ -d does. It logs at DEBUG until this is called. Process-wide.