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