104
104
extern crate bitflags;
105
105
extern crate pcsc_sys as ffi;
106
106
107
+ use std:: borrow:: BorrowMut ;
107
108
use std:: ffi:: { CStr , CString } ;
108
109
use std:: mem:: { forget, transmute} ;
109
110
use std:: ops:: Deref ;
@@ -632,8 +633,10 @@ pub struct Card {
632
633
// - There can only be one active transaction at a time.
633
634
// - All operations on the card must be performed through the transaction
634
635
// for the duration of the transaction's lifetime.
635
- pub struct Transaction < ' tx > {
636
- card : & ' tx mut Card ,
636
+ pub struct Transaction < C > where C : BorrowMut < Card > {
637
+ // This is an option, because we need to tombstone it to
638
+ // effectively disable the Drop implementation.
639
+ card : Option < C > ,
637
640
}
638
641
639
642
/// An iterator over card reader names.
@@ -1161,14 +1164,45 @@ impl Card {
1161
1164
/// [2]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
1162
1165
pub fn transaction (
1163
1166
& mut self ,
1164
- ) -> Result < Transaction , Error > {
1167
+ ) -> Result < Transaction < & mut Card > , Error > {
1165
1168
unsafe {
1166
1169
try_pcsc ! ( ffi:: SCardBeginTransaction (
1167
1170
self . handle,
1168
1171
) ) ;
1169
1172
1170
1173
Ok ( Transaction {
1171
- card : self ,
1174
+ card : Some ( self ) ,
1175
+ } )
1176
+ }
1177
+ }
1178
+
1179
+ /// Start a new exclusive transaction with the card.
1180
+ ///
1181
+ /// This function is like [`Card::transaction`], but it takes
1182
+ /// ownership of the underlying [`Card`]. You can get the `Card`
1183
+ /// back by explicitly ending the transaction using
1184
+ /// [`Transaction::end`] or [`Transaction::end2`].
1185
+ ///
1186
+ /// This function is useful when you want to save a
1187
+ /// [`Transaction`], but can't because Rust's support for
1188
+ /// self-referential data structures is still awkward at best.
1189
+ ///
1190
+ /// Note: you shouldn't keep a transaction open for longer than
1191
+ /// necessary. Microsoft's PCSC implementation, for instance,
1192
+ /// will [automatically end a transaction][1] after 5 seconds of
1193
+ /// inactivity.
1194
+ ///
1195
+ /// [1]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
1196
+ pub fn transaction_owned (
1197
+ self ,
1198
+ ) -> Result < Transaction < Card > , Error > {
1199
+ unsafe {
1200
+ try_pcsc ! ( ffi:: SCardBeginTransaction (
1201
+ self . handle,
1202
+ ) ) ;
1203
+
1204
+ Ok ( Transaction {
1205
+ card : Some ( self ) ,
1172
1206
} )
1173
1207
}
1174
1208
}
@@ -1193,7 +1227,41 @@ impl Card {
1193
1227
/// [2]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
1194
1228
pub fn transaction2 (
1195
1229
& mut self ,
1196
- ) -> Result < Transaction , ( & mut Self , Error ) > {
1230
+ ) -> Result < Transaction < & mut Card > , ( & mut Self , Error ) > {
1231
+ unsafe {
1232
+ let err = ffi:: SCardBeginTransaction (
1233
+ self . handle ,
1234
+ ) ;
1235
+ if err != ffi:: SCARD_S_SUCCESS {
1236
+ return Err ( ( self , Error :: from_raw ( err) ) ) ;
1237
+ }
1238
+
1239
+ return Ok ( Transaction {
1240
+ card : Some ( self ) ,
1241
+ } )
1242
+ }
1243
+ }
1244
+
1245
+ /// Start a new exclusive transaction with the card.
1246
+ ///
1247
+ /// This function is like [`Card::transaction2`], but it takes
1248
+ /// ownership of the underlying [`Card`]. You can get the `Card`
1249
+ /// back by explicitly ending the transaction using
1250
+ /// [`Transaction::end`] or [`Transaction::end2`].
1251
+ ///
1252
+ /// This function is useful when you want to save a
1253
+ /// [`Transaction`], but can't because Rust's support for
1254
+ /// self-referential data structures is still awkward at best.
1255
+ ///
1256
+ /// Note: you shouldn't keep a transaction open for longer than
1257
+ /// necessary. Microsoft's PCSC implementation, for instance,
1258
+ /// will [automatically end a transaction][1] after 5 seconds of
1259
+ /// inactivity.
1260
+ ///
1261
+ /// [1]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
1262
+ pub fn transaction2_owned (
1263
+ self ,
1264
+ ) -> Result < Transaction < Card > , ( Self , Error ) > {
1197
1265
unsafe {
1198
1266
let err = ffi:: SCardBeginTransaction (
1199
1267
self . handle ,
@@ -1203,7 +1271,7 @@ impl Card {
1203
1271
}
1204
1272
1205
1273
return Ok ( Transaction {
1206
- card : self ,
1274
+ card : Some ( self ) ,
1207
1275
} )
1208
1276
}
1209
1277
}
@@ -1639,7 +1707,9 @@ impl Drop for Card {
1639
1707
unsafe impl Send for Card { }
1640
1708
unsafe impl Sync for Card { }
1641
1709
1642
- impl < ' tx > Transaction < ' tx > {
1710
+ impl < C > Transaction < C >
1711
+ where C : BorrowMut < Card >
1712
+ {
1643
1713
/// End the transaction.
1644
1714
///
1645
1715
/// In case of error, ownership of the transaction is returned to the
@@ -1658,46 +1728,66 @@ impl<'tx> Transaction<'tx> {
1658
1728
/// this function if you want to handle errors or use a different
1659
1729
/// disposition method.
1660
1730
pub fn end (
1661
- self ,
1731
+ mut self ,
1662
1732
disposition : Disposition ,
1663
- ) -> Result < ( ) , ( Transaction < ' tx > , Error ) > {
1733
+ ) -> Result < C , ( Self , Error ) > {
1664
1734
unsafe {
1665
1735
let err = ffi:: SCardEndTransaction (
1666
- self . card . handle ,
1736
+ self . card . as_mut ( ) . unwrap ( ) . borrow ( ) . handle ,
1667
1737
disposition. into_raw ( ) ,
1668
1738
) ;
1669
1739
if err != 0 {
1670
1740
return Err ( ( self , Error :: from_raw ( err) ) ) ;
1671
1741
}
1672
1742
1673
1743
// Skip the drop, we did it "manually".
1674
- forget ( self ) ;
1744
+ Ok ( self . card . take ( ) . unwrap ( ) )
1745
+ }
1746
+ }
1675
1747
1676
- Ok ( ( ) )
1748
+ /// End the transaction.
1749
+ ///
1750
+ /// This function is like [`Transaction::end`], but you always get
1751
+ /// back the underlying card.
1752
+ pub fn end2 (
1753
+ self ,
1754
+ disposition : Disposition ,
1755
+ ) -> C {
1756
+ match self . end ( disposition) {
1757
+ Ok ( c) => c,
1758
+ Err ( ( mut tx, _err) ) => tx. card . take ( ) . unwrap ( ) ,
1677
1759
}
1678
1760
}
1679
1761
}
1680
1762
1681
- impl < ' tx > Drop for Transaction < ' tx > {
1763
+ impl < C > Drop for Transaction < C >
1764
+ where C : BorrowMut < Card >
1765
+ {
1682
1766
fn drop ( & mut self ) {
1767
+ if self . card . is_none ( ) {
1768
+ // Already dropped.
1769
+ return ;
1770
+ }
1771
+
1683
1772
unsafe {
1684
1773
// Error is ignored here; to do proper error handling,
1685
1774
// end() should be called manually.
1686
1775
//
1687
1776
// Disposition is hard-coded to LeaveCard here; to use
1688
1777
// another method, end() should be called manually.
1689
1778
let _err = ffi:: SCardEndTransaction (
1690
- self . card . handle ,
1779
+ self . handle ,
1691
1780
Disposition :: LeaveCard . into_raw ( ) ,
1692
1781
) ;
1693
1782
}
1694
1783
}
1695
1784
}
1696
1785
1697
- impl < ' tx > Deref for Transaction < ' tx > {
1786
+ impl < C > Deref for Transaction < C > where C : BorrowMut < Card >
1787
+ {
1698
1788
type Target = Card ;
1699
1789
1700
1790
fn deref ( & self ) -> & Card {
1701
- self . card
1791
+ self . card . as_ref ( ) . unwrap ( ) . borrow ( )
1702
1792
}
1703
1793
}
0 commit comments