Implement ACP 429: add Lazy{Cell,Lock}::get[_mut] and force_mut · qinheping/verify-rust-std@a0f4a4b (original) (raw)

1

1

`use super::UnsafeCell;

`

2

``

`-

use crate::ops::Deref;

`

``

2

`+

use crate::hint::unreachable_unchecked;

`

``

3

`+

use crate::ops::{Deref, DerefMut};

`

3

4

`use crate::{fmt, mem};

`

4

5

``

5

6

`enum State<T, F> {

`

`@@ -82,7 +83,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {

`

82

83

`match this.state.into_inner() {

`

83

84

`State::Init(data) => Ok(data),

`

84

85

`State::Uninit(f) => Err(f),

`

85

``

`-

State::Poisoned => panic!("LazyCell instance has previously been poisoned"),

`

``

86

`+

State::Poisoned => panic_poisoned(),

`

86

87

`}

`

87

88

`}

`

88

89

``

`@@ -114,7 +115,75 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {

`

114

115

`State::Init(data) => data,

`

115

116

`// SAFETY: The state is uninitialized.

`

116

117

`State::Uninit(_) => unsafe { LazyCell::really_init(this) },

`

117

``

`-

State::Poisoned => panic!("LazyCell has previously been poisoned"),

`

``

118

`+

State::Poisoned => panic_poisoned(),

`

``

119

`+

}

`

``

120

`+

}

`

``

121

+

``

122

`+

/// Forces the evaluation of this lazy value and returns a mutable reference to

`

``

123

`+

/// the result.

`

``

124

`+

///

`

``

125

`` +

/// This is equivalent to the DerefMut impl, but is explicit.

``

``

126

`+

///

`

``

127

`+

/// # Examples

`

``

128

`+

///

`

``

129


/// ```

``

130

`+

/// use std::cell::LazyCell;

`

``

131

`+

///

`

``

132

`+

/// let mut lazy = LazyCell::new(|| 92);

`

``

133

`+

///

`

``

134

`+

/// let p = LazyCell::force_mut(&mut lazy);

`

``

135

`+

/// assert_eq!(*p, 92);

`

``

136

`+

/// *p = 44;

`

``

137

`+

/// assert_eq!(*lazy, 44);

`

``

138

`` +

/// *lazy = 55; // Using DerefMut

``

``

139

`+

/// assert_eq!(*lazy, 55);

`

``

140


/// ```

``

141

`+

#[inline]

`

``

142

`+

#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")]

`

``

143

`+

pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {

`

``

144

`+

#[cold]

`

``

145

`+

/// # Safety

`

``

146

`` +

/// May only be called when the state is Uninit.

``

``

147

`+

unsafe fn really_init<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T {

`

``

148

`+

// INVARIANT: Always valid, but the value may not be dropped.

`

``

149

`+

struct PoisonOnPanic<T, F>(*mut State<T, F>);

`

``

150

`+

impl<T, F> Drop for PoisonOnPanic<T, F> {

`

``

151

`+

#[inline]

`

``

152

`+

fn drop(&mut self) {

`

``

153

`+

// SAFETY: Invariant states it is valid, and we don't drop the old value.

`

``

154

`+

unsafe {

`

``

155

`+

self.0.write(State::Poisoned);

`

``

156

`+

}

`

``

157

`+

}

`

``

158

`+

}

`

``

159

+

``

160

`+

let State::Uninit(f) = state else {

`

``

161

`` +

// unreachable!() here won't optimize out because the function is cold.

``

``

162

`+

// SAFETY: Precondition.

`

``

163

`+

unsafe { unreachable_unchecked() };

`

``

164

`+

};

`

``

165

`` +

// SAFETY: We never drop the state after we read f, and we write a valid value back

``

``

166

`` +

// in any case, panic or success. f can't access the LazyCell because it is mutably

``

``

167

`+

// borrowed.

`

``

168

`+

let f = unsafe { core::ptr::read(f) };

`

``

169

`+

// INVARIANT: Initiated from mutable reference, don't drop because we read it.

`

``

170

`+

let guard = PoisonOnPanic(state);

`

``

171

`+

let data = f();

`

``

172

`` +

// SAFETY: PoisonOnPanic invariant, and we don't drop the old value.

``

``

173

`+

unsafe {

`

``

174

`+

core::ptr::write(guard.0, State::Init(data));

`

``

175

`+

}

`

``

176

`+

core::mem::forget(guard);

`

``

177

`+

let State::Init(data) = state else { unreachable!() };

`

``

178

`+

data

`

``

179

`+

}

`

``

180

+

``

181

`+

let state = this.state.get_mut();

`

``

182

`+

match state {

`

``

183

`+

State::Init(data) => data,

`

``

184

`` +

// SAFETY: state is Uninit.

``

``

185

`+

State::Uninit(_) => unsafe { really_init(state) },

`

``

186

`+

State::Poisoned => panic_poisoned(),

`

118

187

`}

`

119

188

`}

`

120

189

``

`@@ -152,13 +221,55 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {

`

152

221

`}

`

153

222

``

154

223

`impl<T, F> LazyCell<T, F> {

`

``

224

`` +

/// Returns a reference to the value if initialized, or None if not.

``

``

225

`+

///

`

``

226

`+

/// # Examples

`

``

227

`+

///

`

``

228


/// ```

``

229

`+

/// #![feature(lazy_get)]

`

``

230

`+

///

`

``

231

`+

/// use std::cell::LazyCell;

`

``

232

`+

///

`

``

233

`+

/// let mut lazy = LazyCell::new(|| 92);

`

``

234

`+

///

`

``

235

`+

/// assert_eq!(LazyCell::get_mut(&mut lazy), None);

`

``

236

`+

/// let _ = LazyCell::force(&lazy);

`

``

237

`+

/// *LazyCell::get_mut(&mut lazy).unwrap() = 44;

`

``

238

`+

/// assert_eq!(*lazy, 44);

`

``

239


/// ```

``

240

`+

#[inline]

`

``

241

`+

#[unstable(feature = "lazy_get", issue = "129333")]

`

``

242

`+

pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {

`

``

243

`+

let state = this.state.get_mut();

`

``

244

`+

match state {

`

``

245

`+

State::Init(data) => Some(data),

`

``

246

`+

_ => None,

`

``

247

`+

}

`

``

248

`+

}

`

``

249

+

``

250

`` +

/// Returns a mutable reference to the value if initialized, or None if not.

``

``

251

`+

///

`

``

252

`+

/// # Examples

`

``

253

`+

///

`

``

254


/// ```

``

255

`+

/// #![feature(lazy_get)]

`

``

256

`+

///

`

``

257

`+

/// use std::cell::LazyCell;

`

``

258

`+

///

`

``

259

`+

/// let lazy = LazyCell::new(|| 92);

`

``

260

`+

///

`

``

261

`+

/// assert_eq!(LazyCell::get(&lazy), None);

`

``

262

`+

/// let _ = LazyCell::force(&lazy);

`

``

263

`+

/// assert_eq!(LazyCell::get(&lazy), Some(&92));

`

``

264


/// ```

155

265

`#[inline]

`

156

``

`-

fn get(&self) -> Option<&T> {

`

``

266

`+

#[unstable(feature = "lazy_get", issue = "129333")]

`

``

267

`+

pub fn get(this: &LazyCell<T, F>) -> Option<&T> {

`

157

268

`// SAFETY:

`

158

269

`` // This is sound for the same reason as in force: once the state is

``

159

270

`// initialized, it will not be mutably accessed again, so this reference

`

160

271

`` // will stay valid for the duration of the borrow to self.

``

161

``

`-

let state = unsafe { &*self.state.get() };

`

``

272

`+

let state = unsafe { &*this.state.get() };

`

162

273

`match state {

`

163

274

`State::Init(data) => Some(data),

`

164

275

` _ => None,

`

`@@ -175,6 +286,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {

`

175

286

`}

`

176

287

`}

`

177

288

``

``

289

`+

#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")]

`

``

290

`+

impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {

`

``

291

`+

#[inline]

`

``

292

`+

fn deref_mut(&mut self) -> &mut T {

`

``

293

`+

LazyCell::force_mut(self)

`

``

294

`+

}

`

``

295

`+

}

`

``

296

+

178

297

`#[stable(feature = "lazy_cell", since = "1.80.0")]

`

179

298

`impl<T: Default> Default for LazyCell {

`

180

299

`` /// Creates a new lazy value using Default as the initializing function.

``

`@@ -188,10 +307,16 @@ impl<T: Default> Default for LazyCell {

`

188

307

`impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {

`

189

308

`fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

`

190

309

`let mut d = f.debug_tuple("LazyCell");

`

191

``

`-

match self.get() {

`

``

310

`+

match LazyCell::get(self) {

`

192

311

`Some(data) => d.field(data),

`

193

312

`None => d.field(&format_args!("")),

`

194

313

`};

`

195

314

` d.finish()

`

196

315

`}

`

197

316

`}

`

``

317

+

``

318

`+

#[cold]

`

``

319

`+

#[inline(never)]

`

``

320

`+

fn panic_poisoned() -> ! {

`

``

321

`+

panic!("LazyCell instance has previously been poisoned")

`

``

322

`+

}

`