Skip to content

Commit 543cf43

Browse files
authored
Mark the majority of the remaining Rust types as frozen (#9308)
These types only required mutability for an interior cache. By using `GILOnceCell` we don't require an `&mut` reference for this.
1 parent 7735fff commit 543cf43

File tree

6 files changed

+76
-84
lines changed

6 files changed

+76
-84
lines changed

src/rust/src/x509/certificate.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@ self_cell::self_cell!(
3333
}
3434
);
3535

36-
// TODO: can't be frozen because extensions takes `&mut self`
37-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")]
36+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.x509")]
3837
pub(crate) struct Certificate {
3938
pub(crate) raw: OwnedCertificate,
40-
pub(crate) cached_extensions: Option<pyo3::PyObject>,
39+
pub(crate) cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
4140
}
4241

4342
#[pyo3::prelude::pymethods]
@@ -248,11 +247,11 @@ impl Certificate {
248247
}
249248

250249
#[getter]
251-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
250+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
252251
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
253252
x509::parse_and_cache_extensions(
254253
py,
255-
&mut self.cached_extensions,
254+
&self.cached_extensions,
256255
&self.raw.borrow_dependent().tbs_cert.raw_extensions,
257256
|ext| match ext.extn_id {
258257
oid::PRECERT_POISON_OID => {
@@ -386,7 +385,7 @@ fn load_der_x509_certificate(
386385

387386
Ok(Certificate {
388387
raw,
389-
cached_extensions: None,
388+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
390389
})
391390
}
392391

src/rust/src/x509/common.rs

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -387,48 +387,46 @@ pub(crate) fn parse_and_cache_extensions<
387387
F: Fn(&Extension<'_>) -> Result<Option<&'p pyo3::PyAny>, CryptographyError>,
388388
>(
389389
py: pyo3::Python<'p>,
390-
cached_extensions: &mut Option<pyo3::PyObject>,
390+
cached_extensions: &pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
391391
raw_extensions: &Option<RawExtensions<'_>>,
392392
parse_ext: F,
393393
) -> pyo3::PyResult<pyo3::PyObject> {
394-
if let Some(cached) = cached_extensions {
395-
return Ok(cached.clone_ref(py));
396-
}
397-
398-
let extensions = match Extensions::from_raw_extensions(raw_extensions.as_ref()) {
399-
Ok(extensions) => extensions,
400-
Err(DuplicateExtensionsError(oid)) => {
401-
let oid_obj = oid_to_py_oid(py, &oid)?;
402-
return Err(exceptions::DuplicateExtension::new_err((
403-
format!("Duplicate {} extension found", &oid),
404-
oid_obj.into_py(py),
405-
)));
406-
}
407-
};
408-
409-
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
410-
let exts = pyo3::types::PyList::empty(py);
411-
for raw_ext in extensions.iter() {
412-
let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?;
413-
414-
let extn_value = match parse_ext(&raw_ext)? {
415-
Some(e) => e,
416-
None => x509_module.call_method1(
417-
pyo3::intern!(py, "UnrecognizedExtension"),
418-
(oid_obj, raw_ext.extn_value),
419-
)?,
420-
};
421-
let ext_obj = x509_module.call_method1(
422-
pyo3::intern!(py, "Extension"),
423-
(oid_obj, raw_ext.critical, extn_value),
424-
)?;
425-
exts.append(ext_obj)?;
426-
}
427-
let extensions = x509_module
428-
.call_method1(pyo3::intern!(py, "Extensions"), (exts,))?
429-
.to_object(py);
430-
*cached_extensions = Some(extensions.clone_ref(py));
431-
Ok(extensions)
394+
cached_extensions
395+
.get_or_try_init(py, || {
396+
let extensions = match Extensions::from_raw_extensions(raw_extensions.as_ref()) {
397+
Ok(extensions) => extensions,
398+
Err(DuplicateExtensionsError(oid)) => {
399+
let oid_obj = oid_to_py_oid(py, &oid)?;
400+
return Err(exceptions::DuplicateExtension::new_err((
401+
format!("Duplicate {} extension found", &oid),
402+
oid_obj.into_py(py),
403+
)));
404+
}
405+
};
406+
407+
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
408+
let exts = pyo3::types::PyList::empty(py);
409+
for raw_ext in extensions.iter() {
410+
let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?;
411+
412+
let extn_value = match parse_ext(&raw_ext)? {
413+
Some(e) => e,
414+
None => x509_module.call_method1(
415+
pyo3::intern!(py, "UnrecognizedExtension"),
416+
(oid_obj, raw_ext.extn_value),
417+
)?,
418+
};
419+
let ext_obj = x509_module.call_method1(
420+
pyo3::intern!(py, "Extension"),
421+
(oid_obj, raw_ext.critical, extn_value),
422+
)?;
423+
exts.append(ext_obj)?;
424+
}
425+
Ok(x509_module
426+
.call_method1(pyo3::intern!(py, "Extensions"), (exts,))?
427+
.to_object(py))
428+
})
429+
.map(|p| p.clone_ref(py))
432430
}
433431

434432
pub(crate) fn encode_extensions<

src/rust/src/x509/crl.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn load_der_x509_crl(
4343
Ok(CertificateRevocationList {
4444
owned: Arc::new(owned),
4545
revoked_certs: pyo3::once_cell::GILOnceCell::new(),
46-
cached_extensions: None,
46+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
4747
})
4848
}
4949

@@ -71,13 +71,12 @@ self_cell::self_cell!(
7171
}
7272
);
7373

74-
// TODO: can't be frozen because extensions required `&mut self`.
75-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")]
74+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.x509")]
7675
struct CertificateRevocationList {
7776
owned: Arc<OwnedCertificateRevocationList>,
7877

7978
revoked_certs: pyo3::once_cell::GILOnceCell<Vec<OwnedRevokedCertificate>>,
80-
cached_extensions: Option<pyo3::PyObject>,
79+
cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
8180
}
8281

8382
impl CertificateRevocationList {
@@ -88,7 +87,7 @@ impl CertificateRevocationList {
8887
fn revoked_cert(&self, py: pyo3::Python<'_>, idx: usize) -> RevokedCertificate {
8988
RevokedCertificate {
9089
owned: self.revoked_certs.get(py).unwrap()[idx].clone(),
91-
cached_extensions: None,
90+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
9291
}
9392
}
9493

@@ -270,13 +269,13 @@ impl CertificateRevocationList {
270269
}
271270

272271
#[getter]
273-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
272+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
274273
let tbs_cert_list = &self.owned.borrow_dependent().tbs_cert_list;
275274

276275
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
277276
x509::parse_and_cache_extensions(
278277
py,
279-
&mut self.cached_extensions,
278+
&self.cached_extensions,
280279
&tbs_cert_list.raw_crl_extensions,
281280
|ext| match ext.extn_id {
282281
oid::CRL_NUMBER_OID => {
@@ -359,7 +358,7 @@ impl CertificateRevocationList {
359358
}
360359

361360
fn get_revoked_certificate_by_serial_number(
362-
&mut self,
361+
&self,
363362
py: pyo3::Python<'_>,
364363
serial: &pyo3::types::PyLong,
365364
) -> pyo3::PyResult<Option<RevokedCertificate>> {
@@ -381,7 +380,7 @@ impl CertificateRevocationList {
381380
match owned {
382381
Ok(o) => Ok(Some(RevokedCertificate {
383382
owned: o,
384-
cached_extensions: None,
383+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
385384
})),
386385
Err(()) => Ok(None),
387386
}
@@ -466,7 +465,7 @@ impl CRLIterator {
466465
.ok()?;
467466
Some(RevokedCertificate {
468467
owned: revoked,
469-
cached_extensions: None,
468+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
470469
})
471470
}
472471
}
@@ -491,11 +490,10 @@ impl Clone for OwnedRevokedCertificate {
491490
}
492491
}
493492

494-
// TODO: can't be frozen because extensions required `&mut self`.
495-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")]
493+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.x509")]
496494
struct RevokedCertificate {
497495
owned: OwnedRevokedCertificate,
498-
cached_extensions: Option<pyo3::PyObject>,
496+
cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
499497
}
500498

501499
#[pyo3::prelude::pymethods]
@@ -517,10 +515,10 @@ impl RevokedCertificate {
517515
}
518516

519517
#[getter]
520-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
518+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
521519
x509::parse_and_cache_extensions(
522520
py,
523-
&mut self.cached_extensions,
521+
&self.cached_extensions,
524522
&self.owned.borrow_dependent().raw_crl_entry_extensions,
525523
|ext| parse_crl_entry_ext(py, ext),
526524
)

src/rust/src/x509/csr.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ self_cell::self_cell!(
2222
}
2323
);
2424

25-
// TODO: can't be frozen extensions take `&mut self`
26-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")]
25+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.x509")]
2726
struct CertificateSigningRequest {
2827
raw: OwnedCsr,
29-
cached_extensions: Option<pyo3::PyObject>,
28+
cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
3029
}
3130

3231
#[pyo3::prelude::pymethods]
@@ -179,7 +178,7 @@ impl CertificateSigningRequest {
179178
}
180179

181180
#[getter]
182-
fn attributes<'p>(&mut self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
181+
fn attributes<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
183182
let pyattrs = pyo3::types::PyList::empty(py);
184183
for attribute in self
185184
.raw
@@ -212,7 +211,7 @@ impl CertificateSigningRequest {
212211
}
213212

214213
#[getter]
215-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
214+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
216215
let raw_exts = self
217216
.raw
218217
.borrow_dependent()
@@ -224,7 +223,7 @@ impl CertificateSigningRequest {
224223
)
225224
})?;
226225

227-
x509::parse_and_cache_extensions(py, &mut self.cached_extensions, &raw_exts, |ext| {
226+
x509::parse_and_cache_extensions(py, &self.cached_extensions, &raw_exts, |ext| {
228227
certificate::parse_cert_ext(py, ext)
229228
})
230229
}
@@ -283,7 +282,7 @@ fn load_der_x509_csr(
283282

284283
Ok(CertificateSigningRequest {
285284
raw,
286-
cached_extensions: None,
285+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
287286
})
288287
}
289288

src/rust/src/x509/ocsp_req.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,15 @@ fn load_der_ocsp_request(
4545

4646
Ok(OCSPRequest {
4747
raw,
48-
cached_extensions: None,
48+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
4949
})
5050
}
5151

52-
// TODO: can't be frozen because extensions takes `&mut self`
53-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")]
52+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.ocsp")]
5453
struct OCSPRequest {
5554
raw: OwnedOCSPRequest,
5655

57-
cached_extensions: Option<pyo3::PyObject>,
56+
cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
5857
}
5958

6059
impl OCSPRequest {
@@ -112,13 +111,13 @@ impl OCSPRequest {
112111
}
113112

114113
#[getter]
115-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
114+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
116115
let tbs_request = &self.raw.borrow_dependent().tbs_request;
117116

118117
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
119118
x509::parse_and_cache_extensions(
120119
py,
121-
&mut self.cached_extensions,
120+
&self.cached_extensions,
122121
&tbs_request.raw_request_extensions,
123122
|ext| {
124123
match ext.extn_id {

src/rust/src/x509/ocsp_resp.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ fn load_der_ocsp_response(
5757
};
5858
Ok(OCSPResponse {
5959
raw: Arc::new(raw),
60-
cached_extensions: None,
61-
cached_single_extensions: None,
60+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
61+
cached_single_extensions: pyo3::once_cell::GILOnceCell::new(),
6262
})
6363
}
6464

@@ -70,13 +70,12 @@ self_cell::self_cell!(
7070
}
7171
);
7272

73-
// TODO: can't be frozen extensions and single_extensions take `&mut self`
74-
#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")]
73+
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.ocsp")]
7574
struct OCSPResponse {
7675
raw: Arc<OwnedOCSPResponse>,
7776

78-
cached_extensions: Option<pyo3::PyObject>,
79-
cached_single_extensions: Option<pyo3::PyObject>,
77+
cached_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
78+
cached_single_extensions: pyo3::once_cell::GILOnceCell<pyo3::PyObject>,
8079
}
8180

8281
impl OCSPResponse {
@@ -247,7 +246,7 @@ impl OCSPResponse {
247246
py,
248247
x509::certificate::Certificate {
249248
raw: raw_cert,
250-
cached_extensions: None,
249+
cached_extensions: pyo3::once_cell::GILOnceCell::new(),
251250
},
252251
)?)?;
253252
}
@@ -321,7 +320,7 @@ impl OCSPResponse {
321320
}
322321

323322
#[getter]
324-
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
323+
fn extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
325324
self.requires_successful_response()?;
326325

327326
let response_data = &self
@@ -337,7 +336,7 @@ impl OCSPResponse {
337336
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
338337
x509::parse_and_cache_extensions(
339338
py,
340-
&mut self.cached_extensions,
339+
&self.cached_extensions,
341340
&response_data.raw_response_extensions,
342341
|ext| {
343342
match &ext.extn_id {
@@ -360,7 +359,7 @@ impl OCSPResponse {
360359
}
361360

362361
#[getter]
363-
fn single_extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
362+
fn single_extensions(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
364363
self.requires_successful_response()?;
365364
let single_resp = single_response(
366365
self.raw
@@ -375,7 +374,7 @@ impl OCSPResponse {
375374
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
376375
x509::parse_and_cache_extensions(
377376
py,
378-
&mut self.cached_single_extensions,
377+
&self.cached_single_extensions,
379378
&single_resp.raw_single_extensions,
380379
|ext| match &ext.extn_id {
381380
&oid::SIGNED_CERTIFICATE_TIMESTAMPS_OID => {

0 commit comments

Comments
 (0)