odbc_sys/handles.rs
1use std::{ffi::c_void, ptr::null_mut};
2
3// ODBC handles are pointers to opaque C types. We do not know their memory layout or other details
4// of their implementation. This RFC suggest how to represent them in Rust:
5// <https://rust-lang.github.io/rfcs/1861-extern-types.html>
6//
7// Until this is stable we could choose to represent them like suggested in the nomicon:
8// <https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs>
9//
10// However, we know in the context of ODBC that we are always interested in the *mut versions of
11// this pointer. For now a strict alias around `*mut c_void` seems to be the most pragmatic
12// solution.
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(transparent)]
16pub struct Handle(pub *mut c_void);
17
18impl Handle {
19 pub fn null() -> Self {
20 Self(null_mut())
21 }
22
23 pub fn as_henv(self) -> HEnv {
24 HEnv(self.0)
25 }
26
27 pub fn as_hdbc(self) -> HDbc {
28 HDbc(self.0)
29 }
30
31 pub fn as_hstmt(self) -> HStmt {
32 HStmt(self.0)
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[repr(transparent)]
38pub struct HEnv(pub *mut c_void);
39
40impl HEnv {
41 pub fn null() -> Self {
42 Self(null_mut())
43 }
44
45 pub fn as_handle(self) -> Handle {
46 Handle(self.0)
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51#[repr(transparent)]
52pub struct HDesc(pub *mut c_void);
53
54impl HDesc {
55 pub fn null() -> Self {
56 Self(null_mut())
57 }
58
59 pub fn as_handle(self) -> Handle {
60 Handle(self.0)
61 }
62}
63
64/// The connection handle references storage of all information about the connection to the data
65/// source, including status, transaction state, and error information.
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[repr(transparent)]
68pub struct HDbc(pub *mut c_void);
69
70impl HDbc {
71 pub fn as_handle(self) -> Handle {
72 Handle(self.0)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77#[repr(transparent)]
78pub struct HStmt(pub *mut c_void);
79
80impl HStmt {
81 pub fn as_handle(self) -> Handle {
82 Handle(self.0)
83 }
84}
85
86// Handles are `Send` according to ODBC spec, since they must be able to be used from different
87// threads. They even must protect their inner state. This would also make them `Sync`, yet they do
88// have interior mutability for error handling.
89// See: <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/multithreading>
90
91unsafe impl Send for HEnv {}
92
93unsafe impl Send for HDbc {}
94
95// Send may not be implemented for HStmt, since statements may bind other parameters and there is no
96// guarantee that the parameter pointers bound to the statement are `Send`. Safe abstractions over
97// statement handles may of course only allow `Send` parameters to bind and then implement `Send`.