automerge/rust/automerge-c/src/doc/map.rs
Alex Good dd3c6d1303
Move rust workspace into ./rust
After some discussion with PVH I realise that the repo structure in the
last reorg was very rust-centric. In an attempt to put each language on
a level footing move the rust code and project files into ./rust
2022-10-16 19:55:51 +01:00

506 lines
19 KiB
Rust

use automerge as am;
use automerge::transaction::Transactable;
use std::os::raw::c_char;
use crate::change_hashes::AMchangeHashes;
use crate::doc::utils::to_str;
use crate::doc::{to_doc, to_doc_mut, to_obj_id, AMdoc};
use crate::obj::{AMobjId, AMobjType};
use crate::result::{to_result, AMresult};
pub mod item;
pub mod items;
/// \memberof AMdoc
/// \brief Deletes a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapDelete(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.delete(to_obj_id!(obj_id), to_str(key)))
}
/// \memberof AMdoc
/// \brief Gets the current or historical value for a key in a map object.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by
/// \p obj_id.
/// \param[in] heads A pointer to an `AMchangeHashes` struct for a historical
/// value or `NULL` for the current value.
/// \return A pointer to an `AMresult` struct that doesn't contain a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
/// heads must be a valid pointer to an AMchangeHashes or std::ptr::null()
#[no_mangle]
pub unsafe extern "C" fn AMmapGet(
doc: *const AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
heads: *const AMchangeHashes,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj_id = to_obj_id!(obj_id);
match heads.as_ref() {
None => to_result(doc.get(obj_id, to_str(key))),
Some(heads) => to_result(doc.get_at(obj_id, to_str(key), heads.as_ref())),
}
}
/// \memberof AMdoc
/// \brief Gets all of the historical values for a key in a map object until
/// its current one or a specific one.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by
/// \p obj_id.
/// \param[in] heads A pointer to an `AMchangeHashes` struct for a historical
/// last value or `NULL` for the current last value.
/// \return A pointer to an `AMresult` struct containing an `AMobjItems` struct.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
/// heads must be a valid pointer to an AMchangeHashes or std::ptr::null()
#[no_mangle]
pub unsafe extern "C" fn AMmapGetAll(
doc: *const AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
heads: *const AMchangeHashes,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj_id = to_obj_id!(obj_id);
match heads.as_ref() {
None => to_result(doc.get_all(obj_id, to_str(key))),
Some(heads) => to_result(doc.get_all_at(obj_id, to_str(key), heads.as_ref())),
}
}
/// \memberof AMdoc
/// \brief Increments a counter for a key in a map object by the given value.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapIncrement(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: i64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.increment(to_obj_id!(obj_id), to_str(key), value))
}
/// \memberof AMdoc
/// \brief Puts a boolean as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A boolean.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutBool(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: bool,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), value))
}
/// \memberof AMdoc
/// \brief Puts a sequence of bytes as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] src A pointer to an array of bytes.
/// \param[in] count The number of bytes to copy from \p src.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \pre \p src `!= NULL`.
/// \pre `0 <` \p count `<= sizeof(`\p src`)`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
/// src must be a byte array of size `>= count`
#[no_mangle]
pub unsafe extern "C" fn AMmapPutBytes(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
src: *const u8,
count: usize,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
let mut vec = Vec::new();
vec.extend_from_slice(std::slice::from_raw_parts(src, count));
to_result(doc.put(to_obj_id!(obj_id), to_str(key), vec))
}
/// \memberof AMdoc
/// \brief Puts a CRDT counter as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutCounter(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: i64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(
to_obj_id!(obj_id),
to_str(key),
am::ScalarValue::Counter(value.into()),
))
}
/// \memberof AMdoc
/// \brief Puts null as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutNull(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), ()))
}
/// \memberof AMdoc
/// \brief Puts an empty object as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] obj_type An `AMobjIdType` enum tag.
/// \return A pointer to an `AMresult` struct containing a pointer to an
/// `AMobjId` struct.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutObject(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
obj_type: AMobjType,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put_object(to_obj_id!(obj_id), to_str(key), obj_type.into()))
}
/// \memberof AMdoc
/// \brief Puts a float as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit float.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutF64(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: f64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), value))
}
/// \memberof AMdoc
/// \brief Puts a signed integer as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutInt(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: i64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), value))
}
/// \memberof AMdoc
/// \brief Puts a UTF-8 string as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A UTF-8 string.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \pre \p value `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
/// value must be a null-terminated array of `c_char`
#[no_mangle]
pub unsafe extern "C" fn AMmapPutStr(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: *const c_char,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), to_str(value)))
}
/// \memberof AMdoc
/// \brief Puts a Lamport timestamp as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutTimestamp(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: i64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(
to_obj_id!(obj_id),
to_str(key),
am::ScalarValue::Timestamp(value),
))
}
/// \memberof AMdoc
/// \brief Puts an unsigned integer as the value of a key in a map object.
///
/// \param[in,out] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj_id.
/// \param[in] value A 64-bit unsigned integer.
/// \return A pointer to an `AMresult` struct containing a void.
/// \pre \p doc `!= NULL`.
/// \pre \p key `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMmapPutUint(
doc: *mut AMdoc,
obj_id: *const AMobjId,
key: *const c_char,
value: u64,
) -> *mut AMresult {
let doc = to_doc_mut!(doc);
to_result(doc.put(to_obj_id!(obj_id), to_str(key), value))
}
/// \memberof AMdoc
/// \brief Gets the current or historical keys and values of the map object
/// within the given range.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj_id A pointer to an `AMobjId` struct or `AM_ROOT`.
/// \param[in] begin The first key in a subrange or `NULL` to indicate the
/// absolute first key.
/// \param[in] end The key one past the last key in a subrange or `NULL` to
/// indicate one past the absolute last key.
/// \param[in] heads A pointer to an `AMchangeHashes` struct for historical
/// keys and values or `NULL` for current keys and values.
/// \return A pointer to an `AMresult` struct containing an `AMmapItems`
/// struct.
/// \pre \p doc `!= NULL`.
/// \pre `strcmp(`\p begin, \p end`) != 1` if \p begin `!= NULL` and \p end `!= NULL`.
/// \warning The returned `AMresult` struct must be deallocated with `AMfree()`
/// in order to prevent a memory leak.
/// \internal
/// # Safety
/// doc must be a valid pointer to an AMdoc
/// obj_id must be a valid pointer to an AMobjId or std::ptr::null()
/// heads must be a valid pointer to an AMchangeHashes or std::ptr::null()
#[no_mangle]
pub unsafe extern "C" fn AMmapRange(
doc: *const AMdoc,
obj_id: *const AMobjId,
begin: *const c_char,
end: *const c_char,
heads: *const AMchangeHashes,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj_id = to_obj_id!(obj_id);
match (begin.as_ref(), end.as_ref()) {
(Some(_), Some(_)) => {
let (begin, end) = (to_str(begin), to_str(end));
if begin > end {
return AMresult::err(&format!("Invalid range [{}-{})", begin, end)).into();
};
let bounds = begin..end;
if let Some(heads) = heads.as_ref() {
to_result(doc.map_range_at(obj_id, bounds, heads.as_ref()))
} else {
to_result(doc.map_range(obj_id, bounds))
}
}
(Some(_), None) => {
let bounds = to_str(begin)..;
if let Some(heads) = heads.as_ref() {
to_result(doc.map_range_at(obj_id, bounds, heads.as_ref()))
} else {
to_result(doc.map_range(obj_id, bounds))
}
}
(None, Some(_)) => {
let bounds = ..to_str(end);
if let Some(heads) = heads.as_ref() {
to_result(doc.map_range_at(obj_id, bounds, heads.as_ref()))
} else {
to_result(doc.map_range(obj_id, bounds))
}
}
(None, None) => {
let bounds = ..;
if let Some(heads) = heads.as_ref() {
to_result(doc.map_range_at(obj_id, bounds, heads.as_ref()))
} else {
to_result(doc.map_range(obj_id, bounds))
}
}
}
}