///|
/// 表示一个有界的命令历史记录集合。
///
/// `History` 是可复制的共享 handle。不同副本共享记录和容量,不会复制底层资源。
///
/// **Construction:**
///
/// 请使用 `History::new` 构造。
///
/// **Lifecycle:**
///
/// 最后一个引用消失后,底层资源会被自动释放;调用者不需要也不能显式关闭。
pub struct History {
priv owner : HistoryOwner
}
///|
fn history_owner_with_capacity(
capacity : Int,
) -> HistoryOwner raise ReadlineError {
guard capacity > 0 else { raise InvalidHistoryCapacity(capacity) }
let owner = HistoryOwner::new(capacity)
match owner.status() {
0 => owner
1 => raise InitializationFailed
_ => raise HistoryUpdateFailed
}
}
///|
fn history_error_code(owner : HistoryOwner) -> Int? {
match owner.last_errno() {
0 => None
code => Some(code)
}
}
///|
/// 创建一个空的、有界的 History。
///
/// **Parameters:**
///
/// - `capacity`:最多保留的记录条数,必须大于零,默认为 1000。
///
/// **Errors:**
///
/// - `capacity` 不大于零时抛出 `InvalidHistoryCapacity`。
/// - 无法创建底层资源时抛出 `InitializationFailed`。
/// - 无法设置容量时抛出 `HistoryUpdateFailed`。
///
/// **Lifecycle:**
///
/// 返回值的所有副本共享同一个私有 owner,并由 finalizer 自动释放底层资源。
///
/// **Examples:**
///
/// ```mbt check
/// test {
/// let history = History::new(capacity=100)
/// inspect(history.length(), content="0")
/// }
/// ```
pub fn History::new(capacity? : Int = 1000) -> History raise ReadlineError {
{ owner: history_owner_with_capacity(capacity) }
}
///|
/// 原样添加一条记录。
///
/// 空字符串和重复记录都会被保留;此操作不会 trim 或去重。超过容量时会自动丢弃最旧的
/// 记录。
///
/// **Errors:**
///
/// - `line` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法更新 History 时抛出 `HistoryUpdateFailed`。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::add(
self : History,
line : StringView,
) -> Unit raise ReadlineError {
match self.owner.add(@utf8.encode(line)) {
0 => ()
1 => raise EmbeddedNul
3 => raise Busy
_ => raise HistoryUpdateFailed
}
}
///|
/// 清空当前 History 中的全部记录。
///
/// **Errors:**
///
/// 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::clear(self : History) -> Unit raise ReadlineError {
guard self.owner.clear() != 3 else { raise Busy }
}
///|
/// 返回当前保存的记录条数。
///
/// **Errors:**
///
/// - 无法查询底层 History 状态时抛出 `HistoryUpdateFailed`。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::length(self : History) -> Int raise ReadlineError {
let length = self.owner.length()
guard length != -2 else { raise Busy }
guard length >= 0 else { raise HistoryUpdateFailed }
length
}
///|
/// 创建一个新的 History,并从文件加载记录。
///
/// 加载成功后,超过容量的旧记录不会被保留。加载失败时不会返回半初始化对象,也不会
/// 修改任何已有 History。
///
/// **Parameters:**
///
/// - `path`:要读取的 History 文件路径。
/// - `capacity`:最多保留的记录条数,必须大于零,默认为 1000。
///
/// **Errors:**
///
/// - `capacity` 不大于零时抛出 `InvalidHistoryCapacity`。
/// - `path` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法创建或配置底层资源时抛出 `InitializationFailed` 或
/// `HistoryUpdateFailed`。
/// - 无法读取或解析文件时抛出 `HistoryLoadFailed`;错误中包含路径,以及底层能够可靠
/// 提供时的 OS error code。
///
/// **Side effects:**
///
/// 此操作会读取 `path` 指向的文件。
pub fn History::load(
path : StringView,
capacity? : Int = 1000,
) -> History raise ReadlineError {
let owned_path = path.to_owned()
let owner = history_owner_with_capacity(capacity)
match owner.load(@utf8.encode(owned_path)) {
0 => { owner, }
1 => raise EmbeddedNul
_ => raise HistoryLoadFailed(owned_path, history_error_code(owner))
}
}
///|
/// 将当前全部记录保存到文件,并覆盖目标文件原有内容。
///
/// 保存失败不会改变内存中的 History,但目标文件可能已经被创建或截断。
///
/// **Parameters:**
///
/// - `path`:要覆盖写入的文件路径。
///
/// **Errors:**
///
/// - `path` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法写入文件时抛出 `HistorySaveFailed`;错误中包含路径,以及底层能够可靠提供时的
/// OS error code。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
///
/// **Side effects:**
///
/// 此操作会创建或覆盖 `path` 指向的文件。
pub fn History::save(
self : History,
path : StringView,
) -> Unit raise ReadlineError {
let owned_path = path.to_owned()
match self.owner.save(@utf8.encode(owned_path)) {
0 => ()
1 => raise EmbeddedNul
3 => raise Busy
_ => raise HistorySaveFailed(owned_path, history_error_code(self.owner))
}
}