@@ -1193,6 +1193,8 @@ pub(crate) fn errno_to_exc_type(_errno: i32, _vm: &VirtualMachine) -> Option<&'s
11931193 None
11941194}
11951195
1196+ pub ( crate ) use types:: { OSErrorBuilder , ToOSErrorBuilder } ;
1197+
11961198pub ( super ) mod types {
11971199 use crate :: common:: lock:: PyRwLock ;
11981200 use crate :: object:: { MaybeTraverse , Traverse , TraverseFn } ;
@@ -1204,14 +1206,143 @@ pub(super) mod types {
12041206 PyInt , PyStrRef , PyTupleRef , PyType , PyTypeRef , traceback:: PyTracebackRef ,
12051207 tuple:: IntoPyTuple ,
12061208 } ,
1209+ convert:: ToPyObject ,
12071210 convert:: ToPyResult ,
12081211 function:: { ArgBytesLike , FuncArgs } ,
1212+ ospath:: OsPathOrFd ,
12091213 types:: { Constructor , Initializer } ,
12101214 } ;
12111215 use crossbeam_utils:: atomic:: AtomicCell ;
12121216 use itertools:: Itertools ;
12131217 use rustpython_common:: str:: UnicodeEscapeCodepoint ;
12141218
1219+ pub ( crate ) trait ToOSErrorBuilder {
1220+ fn to_os_error_builder < ' a > ( & self , vm : & VirtualMachine ) -> OSErrorBuilder ;
1221+ }
1222+
1223+ pub struct OSErrorBuilder {
1224+ exc_type : PyTypeRef ,
1225+ errno : Option < i32 > ,
1226+ strerror : Option < PyObjectRef > ,
1227+ filename : Option < PyObjectRef > ,
1228+ filename2 : Option < PyObjectRef > ,
1229+ #[ cfg( windows) ]
1230+ winerror : Option < i32 > ,
1231+ }
1232+
1233+ impl OSErrorBuilder {
1234+ #[ must_use]
1235+ pub fn with_subtype (
1236+ exc_type : PyTypeRef ,
1237+ errno : Option < i32 > ,
1238+ strerror : impl ToPyObject ,
1239+ vm : & VirtualMachine ,
1240+ ) -> Self {
1241+ let strerror = strerror. to_pyobject ( vm) ;
1242+ Self {
1243+ exc_type,
1244+ errno : errno,
1245+ strerror : Some ( strerror. to_pyobject ( vm) ) ,
1246+ filename : None ,
1247+ filename2 : None ,
1248+ #[ cfg( windows) ]
1249+ winerror : None ,
1250+ }
1251+ }
1252+ #[ must_use]
1253+ pub fn with_errno ( errno : i32 , strerror : impl ToPyObject , vm : & VirtualMachine ) -> Self {
1254+ let exc_type = crate :: exceptions:: errno_to_exc_type ( errno, vm)
1255+ . unwrap_or ( vm. ctx . exceptions . os_error )
1256+ . to_owned ( ) ;
1257+ Self :: with_subtype ( exc_type, Some ( errno) , strerror, vm)
1258+ }
1259+
1260+ // #[must_use]
1261+ // pub(crate) fn errno(mut self, errno: i32) -> Self {
1262+ // self.errno.replace(errno);
1263+ // self
1264+ // }
1265+
1266+ #[ must_use]
1267+ pub ( crate ) fn filename ( mut self , filename : PyObjectRef ) -> Self {
1268+ let filename = filename. into ( ) ;
1269+ self . filename . replace ( filename) ;
1270+ self
1271+ }
1272+
1273+ #[ must_use]
1274+ pub ( crate ) fn filename2 ( mut self , filename : PyObjectRef ) -> Self {
1275+ let filename = filename. into ( ) ;
1276+ self . filename2 . replace ( filename) ;
1277+ self
1278+ }
1279+
1280+ // #[must_use]
1281+ // #[cfg(windows)]
1282+ // pub(crate) fn winerror(mut self, filename: PyObjectRef) -> Self {
1283+ // let filename = filename.into();
1284+ // self.winerror.replace(filename);
1285+ // self
1286+ // }
1287+
1288+ #[ must_use]
1289+ pub ( crate ) fn with_filename < ' a > (
1290+ error : & std:: io:: Error ,
1291+ filename : impl Into < OsPathOrFd < ' a > > ,
1292+ vm : & VirtualMachine ,
1293+ ) -> PyBaseExceptionRef {
1294+ // TODO: return type to PyRef<PyOSError>
1295+ let builder = error. to_os_error_builder ( vm) ;
1296+ let builder = builder. filename ( filename. into ( ) . filename ( vm) ) ;
1297+ builder. build ( vm) . upcast ( )
1298+ }
1299+
1300+ pub fn build ( self , vm : & VirtualMachine ) -> PyRef < PyOSError > {
1301+ let OSErrorBuilder {
1302+ exc_type,
1303+ errno,
1304+ strerror,
1305+ filename,
1306+ #[ cfg( windows) ]
1307+ winerror,
1308+ filename2,
1309+ } = self ;
1310+
1311+ #[ cfg( windows) ]
1312+ let winerror = winerror. to_pyobject ( vm) ;
1313+ #[ cfg( not( windows) ) ]
1314+ let winerror = vm. ctx . none ( ) ;
1315+
1316+ let args = vec ! [
1317+ errno. to_pyobject( vm) ,
1318+ strerror. to_pyobject( vm) ,
1319+ filename. to_pyobject( vm) ,
1320+ winerror,
1321+ filename2. to_pyobject( vm) ,
1322+ ] ;
1323+
1324+ let payload =
1325+ PyOSError :: py_new ( & exc_type, args. into ( ) , vm) . expect ( "new_os_error usage error" ) ;
1326+ // unsafe {
1327+ // let _ = payload.filename.swap(filename);
1328+ // let _ = payload.filename2.swap(filename2);
1329+ // }
1330+ // #[cfg(windows)]
1331+ // {
1332+ // let _ = payload.winerror.swap(winerror);
1333+ // }
1334+ payload
1335+ . into_ref_with_type ( vm, exc_type)
1336+ . expect ( "new_os_error usage error" )
1337+ }
1338+ }
1339+
1340+ impl crate :: convert:: IntoPyException for OSErrorBuilder {
1341+ fn into_pyexception ( self , vm : & VirtualMachine ) -> PyBaseExceptionRef {
1342+ self . build ( vm) . upcast ( )
1343+ }
1344+ }
1345+
12151346 // Re-export exception group types from dedicated module
12161347 pub use crate :: exception_group:: types:: PyBaseExceptionGroup ;
12171348
0 commit comments