104104extern crate bitflags;
105105extern crate pcsc_sys as ffi;
106106
107+ use std:: borrow:: BorrowMut ;
107108use std:: ffi:: { CStr , CString } ;
108109use std:: mem:: { forget, transmute} ;
109110use std:: ops:: Deref ;
@@ -632,8 +633,10 @@ pub struct Card {
632633// - There can only be one active transaction at a time.
633634// - All operations on the card must be performed through the transaction
634635// 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 > ,
637640}
638641
639642/// An iterator over card reader names.
@@ -1161,14 +1164,45 @@ impl Card {
11611164 /// [2]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
11621165 pub fn transaction (
11631166 & mut self ,
1164- ) -> Result < Transaction , Error > {
1167+ ) -> Result < Transaction < & mut Card > , Error > {
11651168 unsafe {
11661169 try_pcsc ! ( ffi:: SCardBeginTransaction (
11671170 self . handle,
11681171 ) ) ;
11691172
11701173 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 ) ,
11721206 } )
11731207 }
11741208 }
@@ -1193,7 +1227,41 @@ impl Card {
11931227 /// [2]: https://msdn.microsoft.com/en-us/library/aa379469.aspx
11941228 pub fn transaction2 (
11951229 & 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 ) > {
11971265 unsafe {
11981266 let err = ffi:: SCardBeginTransaction (
11991267 self . handle ,
@@ -1203,7 +1271,7 @@ impl Card {
12031271 }
12041272
12051273 return Ok ( Transaction {
1206- card : self ,
1274+ card : Some ( self ) ,
12071275 } )
12081276 }
12091277 }
@@ -1639,7 +1707,9 @@ impl Drop for Card {
16391707unsafe impl Send for Card { }
16401708unsafe impl Sync for Card { }
16411709
1642- impl < ' tx > Transaction < ' tx > {
1710+ impl < C > Transaction < C >
1711+ where C : BorrowMut < Card >
1712+ {
16431713 /// End the transaction.
16441714 ///
16451715 /// In case of error, ownership of the transaction is returned to the
@@ -1658,46 +1728,66 @@ impl<'tx> Transaction<'tx> {
16581728 /// this function if you want to handle errors or use a different
16591729 /// disposition method.
16601730 pub fn end (
1661- self ,
1731+ mut self ,
16621732 disposition : Disposition ,
1663- ) -> Result < ( ) , ( Transaction < ' tx > , Error ) > {
1733+ ) -> Result < C , ( Self , Error ) > {
16641734 unsafe {
16651735 let err = ffi:: SCardEndTransaction (
1666- self . card . handle ,
1736+ self . card . as_mut ( ) . unwrap ( ) . borrow ( ) . handle ,
16671737 disposition. into_raw ( ) ,
16681738 ) ;
16691739 if err != 0 {
16701740 return Err ( ( self , Error :: from_raw ( err) ) ) ;
16711741 }
16721742
16731743 // Skip the drop, we did it "manually".
1674- forget ( self ) ;
1744+ Ok ( self . card . take ( ) . unwrap ( ) )
1745+ }
1746+ }
16751747
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 ( ) ,
16771759 }
16781760 }
16791761}
16801762
1681- impl < ' tx > Drop for Transaction < ' tx > {
1763+ impl < C > Drop for Transaction < C >
1764+ where C : BorrowMut < Card >
1765+ {
16821766 fn drop ( & mut self ) {
1767+ if self . card . is_none ( ) {
1768+ // Already dropped.
1769+ return ;
1770+ }
1771+
16831772 unsafe {
16841773 // Error is ignored here; to do proper error handling,
16851774 // end() should be called manually.
16861775 //
16871776 // Disposition is hard-coded to LeaveCard here; to use
16881777 // another method, end() should be called manually.
16891778 let _err = ffi:: SCardEndTransaction (
1690- self . card . handle ,
1779+ self . handle ,
16911780 Disposition :: LeaveCard . into_raw ( ) ,
16921781 ) ;
16931782 }
16941783 }
16951784}
16961785
1697- impl < ' tx > Deref for Transaction < ' tx > {
1786+ impl < C > Deref for Transaction < C > where C : BorrowMut < Card >
1787+ {
16981788 type Target = Card ;
16991789
17001790 fn deref ( & self ) -> & Card {
1701- self . card
1791+ self . card . as_ref ( ) . unwrap ( ) . borrow ( )
17021792 }
17031793}
0 commit comments