//! Code related to `sqlite3_context` common to `functions` and `vtab` modules.

use crate::ffi::sqlite3_value;
use std::ffi::c_void;

use crate::ffi;
use crate::ffi::sqlite3_context;

use crate::str_for_sqlite;
use crate::types::{ToSqlOutput, ValueRef};

// This function is inline despite it's size because what's in the ToSqlOutput
// is often known to the compiler, and thus const prop/DCE can substantially
// simplify the function.
#[inline]
pub(super) unsafe fn set_result(
    ctx: *mut sqlite3_context,
    #[allow(unused_variables)] args: &[*mut sqlite3_value],
    result: &ToSqlOutput<'_>,
) {
    let value = match *result {
        ToSqlOutput::Borrowed(v) => v,
        ToSqlOutput::Owned(ref v) => ValueRef::from(v),

        #[cfg(feature = "blob")]
        ToSqlOutput::ZeroBlob(len) => {
            // TODO sqlite3_result_zeroblob64 // 3.8.11
            return ffi::sqlite3_result_zeroblob(ctx, len);
        }
        #[cfg(feature = "functions")]
        ToSqlOutput::Arg(i) => {
            return ffi::sqlite3_result_value(ctx, args[i]);
        }
        #[cfg(feature = "pointer")]
        ToSqlOutput::Pointer(ref p) => {
            return ffi::sqlite3_result_pointer(ctx, p.0 as _, p.1.as_ptr(), p.2);
        }
    };

    match value {
        ValueRef::Null => ffi::sqlite3_result_null(ctx),
        ValueRef::Integer(i) => ffi::sqlite3_result_int64(ctx, i),
        ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r),
        ValueRef::Text(s) => {
            let (c_str, len, destructor) = str_for_sqlite(s);
            ffi::sqlite3_result_text64(ctx, c_str, len, destructor, ffi::SQLITE_UTF8 as _);
            // TODO SQLITE_UTF8_ZT
        }
        ValueRef::Blob(b) => {
            let length = b.len();
            if length == 0 {
                ffi::sqlite3_result_zeroblob(ctx, 0);
            } else {
                ffi::sqlite3_result_blob64(
                    ctx,
                    b.as_ptr().cast::<c_void>(),
                    length as ffi::sqlite3_uint64,
                    ffi::SQLITE_TRANSIENT(),
                );
            }
        }
    }
}
