///|
/// The outcome of a search: all entries and references collected plus the
/// final `SearchResultDone`.
pub struct SearchOutcome {
entries : Array[SearchResultEntry]
references : Array[SearchResultReference]
mut result : LdapResult
} derive(Eq, @debug.Debug)
///|
pub fn SearchOutcome::new() -> SearchOutcome {
{ entries: [], references: [], result: LdapResult::success() }
}
///|
/// A completed search exchange: the final result plus any response controls
/// (e.g. the paged results cookie from RFC 2696).
pub struct SearchDone {
result : LdapResult
controls : Array[Control]?
} derive(Eq, @debug.Debug)
///|
/// Execute a search with optional request controls, streaming results to
/// callbacks. Returns the final result together with response controls.
pub async fn[T : LdapTransport] Session::search_done(
self : Session[T],
request : SearchRequest,
controls? : Array[Control],
on_entry? : (SearchResultEntry) -> Unit,
on_reference? : (SearchResultReference) -> Unit,
) -> Result[SearchDone, LdapError] {
let id = self.next_message_id()
let message = match controls {
Some(c) => LdapMessage::with_controls(id, SearchRequest(request), c)
None => LdapMessage::new(id, SearchRequest(request))
}
let bytes = match encode_message(message) {
Ok(b) => b
Err(e) => return Err(e)
}
match self.transport.write(bytes) {
Ok(_) => ()
Err(e) => return Err(e)
}
while true {
let response = match self.transport.read() {
Ok(b) => b
Err(e) => return Err(e)
}
let decoded = match decode_message(response, None) {
Ok(m) => m
Err(e) => return Err(e)
}
if decoded.message_id != id {
return Err(LdapError::InvalidMessageId(decoded.message_id))
}
match decoded.op {
SearchResultEntry(entry) =>
match on_entry {
Some(cb) => cb(entry)
None => ()
}
SearchResultReference(refs) =>
match on_reference {
Some(cb) => cb(refs)
None => ()
}
SearchResultDone(result) =>
return Ok({ result, controls: decoded.controls })
_ => return Err(LdapError::UnexpectedOp(protocol_op_tag(decoded.op)))
}
}
abort("unreachable")
}
///|
/// Execute a search and stream the results to callbacks. `on_entry` and
/// `on_reference` are invoked as the corresponding messages arrive; the
/// returned `LdapResult` is the final `SearchResultDone`.
pub async fn[T : LdapTransport] Session::search(
self : Session[T],
request : SearchRequest,
on_entry? : (SearchResultEntry) -> Unit,
on_reference? : (SearchResultReference) -> Unit,
) -> Result[LdapResult, LdapError] {
let done = match self.search_done(request, on_entry?, on_reference?) {
Ok(d) => d
Err(e) => return Err(e)
}
Ok(done.result)
}
///|
/// Execute a search and collect all entries, references and the final result.
pub async fn[T : LdapTransport] Session::search_to_array(
self : Session[T],
request : SearchRequest,
) -> Result[SearchOutcome, LdapError] {
let acc = @ref.Ref(SearchOutcome::new())
let result = match
self.search(request, on_entry=fn(entry) { acc.val.entries.push(entry) }, on_reference=fn(
refs,
) {
acc.val.references.push(refs)
}) {
Ok(r) => r
Err(e) => return Err(e)
}
acc.val.result = result
Ok(acc.val)
}