use crate::error::Error;
use crate::error::Error::OperationCancelledError;
use futures::FutureExt;
use futures::future::Either;
use std::future::Future;
use std::path::PathBuf;
use tokio_util::sync::CancellationToken;
pub type TdsResult<T> = Result<T, Error>;
pub const TDS_8_ALPN_PROTOCOL: &str = "tds/8.0";
#[derive(Debug)]
pub struct CancelHandle {
pub(crate) cancel_token: CancellationToken,
}
impl CancelHandle {
pub fn new() -> Self {
CancelHandle {
cancel_token: CancellationToken::new(),
}
}
pub fn cancel(self) {
self.cancel_token.cancel();
}
pub fn child_handle(&self) -> Self {
Self::from(self.cancel_token.child_token())
}
pub(crate) fn run_until_cancelled<'a, F, ResultType>(
cancel_handle: Option<&'a CancelHandle>,
f: F,
) -> impl Future<Output = F::Output> + Send + 'a
where
F: Future<Output = TdsResult<ResultType>> + Send + 'a,
{
match cancel_handle {
Some(handle) => Either::Left(handle.cancel_token.run_until_cancelled(f).map(
|result| match result {
Some(result) => result,
None => Err(OperationCancelledError("Request was cancelled".to_string())),
},
)),
None => Either::Right(f),
}
}
}
impl From<CancellationToken> for CancelHandle {
fn from(value: CancellationToken) -> Self {
CancelHandle {
cancel_token: value,
}
}
}
impl Default for CancelHandle {
fn default() -> Self {
Self::new()
}
}
#[derive(PartialEq, Debug)]
pub enum SQLServerVersion {
SqlServerNotsupported = 0,
SqlServer2000 = 8,
SqlServer2005 = 9,
SqlServer2008 = 10,
SqlServer2012 = 11,
SqlServer2014 = 12,
SqlServer2016 = 13,
SqlServer2017 = 14,
SqlServer2019 = 15,
SqlServer2022 = 16,
SqlServer2022lus = 17,
}
impl From<u8> for SQLServerVersion {
fn from(v: u8) -> Self {
match v {
0 => SQLServerVersion::SqlServerNotsupported,
8 => SQLServerVersion::SqlServer2000,
9 => SQLServerVersion::SqlServer2005,
10 => SQLServerVersion::SqlServer2008,
11 => SQLServerVersion::SqlServer2012,
12 => SQLServerVersion::SqlServer2014,
13 => SQLServerVersion::SqlServer2016,
14 => SQLServerVersion::SqlServer2017,
15 => SQLServerVersion::SqlServer2019,
16 => SQLServerVersion::SqlServer2022,
17 => SQLServerVersion::SqlServer2022lus,
_ => SQLServerVersion::SqlServerNotsupported,
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Version {
pub major: u8,
pub minor: u8,
pub build: u16,
pub revision: u16,
}
impl Version {
pub fn new(major: u8, minor: u8, build: u16, revision: u16) -> Self {
Version {
major,
minor,
build,
revision,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sql_server_version_from_known_values() {
assert_eq!(
SQLServerVersion::from(0),
SQLServerVersion::SqlServerNotsupported
);
assert_eq!(SQLServerVersion::from(8), SQLServerVersion::SqlServer2000);
assert_eq!(SQLServerVersion::from(9), SQLServerVersion::SqlServer2005);
assert_eq!(SQLServerVersion::from(10), SQLServerVersion::SqlServer2008);
assert_eq!(SQLServerVersion::from(11), SQLServerVersion::SqlServer2012);
assert_eq!(SQLServerVersion::from(12), SQLServerVersion::SqlServer2014);
assert_eq!(SQLServerVersion::from(13), SQLServerVersion::SqlServer2016);
assert_eq!(SQLServerVersion::from(14), SQLServerVersion::SqlServer2017);
assert_eq!(SQLServerVersion::from(15), SQLServerVersion::SqlServer2019);
assert_eq!(SQLServerVersion::from(16), SQLServerVersion::SqlServer2022);
assert_eq!(
SQLServerVersion::from(17),
SQLServerVersion::SqlServer2022lus
);
}
#[test]
fn sql_server_version_from_unknown_defaults_to_not_supported() {
assert_eq!(
SQLServerVersion::from(1),
SQLServerVersion::SqlServerNotsupported
);
assert_eq!(
SQLServerVersion::from(7),
SQLServerVersion::SqlServerNotsupported
);
assert_eq!(
SQLServerVersion::from(18),
SQLServerVersion::SqlServerNotsupported
);
assert_eq!(
SQLServerVersion::from(255),
SQLServerVersion::SqlServerNotsupported
);
}
#[test]
fn cancel_handle_default() {
let handle = CancelHandle::default();
assert!(!handle.cancel_token.is_cancelled());
}
#[tokio::test]
async fn run_until_cancelled_none_handle() {
let result: TdsResult<i32> =
CancelHandle::run_until_cancelled(None, async { Ok(42) }).await;
assert_eq!(result.unwrap(), 42);
}
#[tokio::test]
async fn run_until_cancelled_with_handle_completes() {
let handle = CancelHandle::new();
let result: TdsResult<i32> =
CancelHandle::run_until_cancelled(Some(&handle), async { Ok(99) }).await;
assert_eq!(result.unwrap(), 99);
}
#[tokio::test]
async fn run_until_cancelled_with_cancelled_handle_stops_pending_future() {
let handle = CancelHandle::new();
handle.cancel_token.cancel();
let result = CancelHandle::run_until_cancelled(
Some(&handle),
std::future::pending::<TdsResult<i32>>(),
)
.await;
assert!(matches!(result, Err(OperationCancelledError(_))));
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct EncryptionOptions {
pub mode: EncryptionSetting,
pub trust_server_certificate: bool,
pub host_name_in_cert: Option<String>,
pub server_certificate: Option<PathBuf>,
}
impl EncryptionOptions {
pub fn new() -> Self {
EncryptionOptions {
mode: EncryptionSetting::Strict,
trust_server_certificate: false,
host_name_in_cert: None,
server_certificate: None,
}
}
}
impl Default for EncryptionOptions {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum EncryptionSetting {
PreferOff,
On,
Required,
Strict,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum NegotiatedEncryptionSetting {
Strict,
LoginOnly,
Mandatory,
NoEncryption,
}