@@ -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,135 @@ 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 ( & 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+ #[ cfg( windows) ]
1229+ winerror : Option < PyObjectRef > ,
1230+ filename2 : Option < PyObjectRef > ,
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,
1245+ strerror : Some ( strerror. to_pyobject ( vm) ) ,
1246+ filename : None ,
1247+ #[ cfg( windows) ]
1248+ winerror : None ,
1249+ filename2 : 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+ self . filename . replace ( filename) ;
1269+ self
1270+ }
1271+
1272+ #[ must_use]
1273+ pub ( crate ) fn filename2 ( mut self , filename : PyObjectRef ) -> Self {
1274+ self . filename2 . replace ( filename) ;
1275+ self
1276+ }
1277+
1278+ #[ must_use]
1279+ #[ cfg( windows) ]
1280+ pub ( crate ) fn winerror ( mut self , winerror : PyObjectRef ) -> Self {
1281+ self . winerror . replace ( winerror) ;
1282+ self
1283+ }
1284+
1285+ #[ must_use]
1286+ pub ( crate ) fn with_filename < ' a > (
1287+ error : & std:: io:: Error ,
1288+ filename : impl Into < OsPathOrFd < ' a > > ,
1289+ vm : & VirtualMachine ,
1290+ ) -> PyBaseExceptionRef {
1291+ // TODO: return type to PyRef<PyOSError>
1292+ let builder = error. to_os_error_builder ( vm) ;
1293+ let builder = builder. filename ( filename. into ( ) . filename ( vm) ) ;
1294+ builder. build ( vm) . upcast ( )
1295+ }
1296+
1297+ pub fn build ( self , vm : & VirtualMachine ) -> PyRef < PyOSError > {
1298+ let OSErrorBuilder {
1299+ exc_type,
1300+ errno,
1301+ strerror,
1302+ filename,
1303+ #[ cfg( windows) ]
1304+ winerror,
1305+ filename2,
1306+ } = self ;
1307+
1308+ #[ cfg( windows) ]
1309+ let winerror = winerror. to_pyobject ( vm) ;
1310+ #[ cfg( not( windows) ) ]
1311+ let winerror = vm. ctx . none ( ) ;
1312+
1313+ let args = vec ! [
1314+ errno. to_pyobject( vm) ,
1315+ strerror. to_pyobject( vm) ,
1316+ filename. to_pyobject( vm) ,
1317+ winerror,
1318+ filename2. to_pyobject( vm) ,
1319+ ] ;
1320+
1321+ let payload = PyOSError :: py_new ( & exc_type, args. clone ( ) . into ( ) , vm)
1322+ . expect ( "new_os_error usage error" ) ;
1323+ let os_error = payload
1324+ . into_ref_with_type ( vm, exc_type)
1325+ . expect ( "new_os_error usage error" ) ;
1326+ PyOSError :: slot_init ( os_error. as_object ( ) . to_owned ( ) , args. into ( ) , vm)
1327+ . expect ( "new_os_error usage error" ) ;
1328+ os_error
1329+ }
1330+ }
1331+
1332+ impl crate :: convert:: IntoPyException for OSErrorBuilder {
1333+ fn into_pyexception ( self , vm : & VirtualMachine ) -> PyBaseExceptionRef {
1334+ self . build ( vm) . upcast ( )
1335+ }
1336+ }
1337+
12151338 // Re-export exception group types from dedicated module
12161339 pub use crate :: exception_group:: types:: PyBaseExceptionGroup ;
12171340
0 commit comments