aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Abrahamsen2020-08-27 17:17:19 -0700
committerEric Abrahamsen2020-08-28 08:20:28 -0700
commit4d741e577fbab8adf444c6c1930525bb7e8fc08d (patch)
treee526dc264c9a510b7cbfbfe394e23144a506fa92
parent649a52822f207e1d302f0e089010b84d5e882281 (diff)
downloademacs-4d741e577fbab8adf444c6c1930525bb7e8fc08d.tar.gz
emacs-4d741e577fbab8adf444c6c1930525bb7e8fc08d.zip
Remove redundant slot validation in eieio-persistent-read
Actual object creation (in `make-instance') will later run all slot values through cl-typep, which does a better job of validation. This validation is redundant, and slows the read process down. * lisp/emacs-lisp/eieio-base.el (eieio-persistent-fix-value): Rename from `eieio-persistent-validate/fix-slot-value', as we no longer validate, and we don't care about the slot definition. (eieio-persistent-slot-type-is-class-p): Delete function. (eieio-persistent-convert-list-to-object): Still call `eieio--full-class-object', to trigger an autoload if necessary, but discard the return value.
-rw-r--r--lisp/emacs-lisp/eieio-base.el211
1 files changed, 63 insertions, 148 deletions
diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el
index 2cb1f614ce3..f09d1997eee 100644
--- a/lisp/emacs-lisp/eieio-base.el
+++ b/lisp/emacs-lisp/eieio-base.el
@@ -266,105 +266,75 @@ malicious code.
266 266
267Note: This function recurses when a slot of :type of some object is 267Note: This function recurses when a slot of :type of some object is
268identified, and needing more object creation." 268identified, and needing more object creation."
269 (let* ((objclass (nth 0 inputlist)) 269 (let ((objclass (nth 0 inputlist))
270 ;; Earlier versions of `object-write' added a string name for 270 ;; Earlier versions of `object-write' added a string name for
271 ;; the object, now obsolete. 271 ;; the object, now obsolete.
272 (slots (nthcdr 272 (slots (nthcdr
273 (if (stringp (nth 1 inputlist)) 2 1) 273 (if (stringp (nth 1 inputlist)) 2 1)
274 inputlist)) 274 inputlist))
275 (createslots nil) 275 (createslots nil))
276 (class 276 ;; If OBJCLASS is an eieio autoload object, then we need to
277 (progn 277 ;; load it (we don't need the return value).
278 ;; If OBJCLASS is an eieio autoload object, then we need to 278 (eieio--full-class-object objclass)
279 ;; load it.
280 (eieio--full-class-object objclass))))
281
282 (while slots 279 (while slots
283 (let ((initarg (car slots)) 280 (let ((initarg (car slots))
284 (value (car (cdr slots)))) 281 (value (car (cdr slots))))
285 282
286 ;; Make sure that the value proposed for SLOT is valid. 283 ;; Strip out quotes, list functions, and update object
287 ;; In addition, strip out quotes, list functions, and update 284 ;; constructors as needed.
288 ;; object constructors as needed. 285 (setq value (eieio-persistent-fix-value value))
289 (setq value (eieio-persistent-validate/fix-slot-value
290 class (eieio--initarg-to-attribute class initarg) value))
291 286
292 (push initarg createslots) 287 (push initarg createslots)
293 (push value createslots) 288 (push value createslots))
294 )
295 289
296 (setq slots (cdr (cdr slots)))) 290 (setq slots (cdr (cdr slots))))
297 291
298 (apply #'make-instance objclass (nreverse createslots)) 292 (apply #'make-instance objclass (nreverse createslots))))
299 293
300 ;;(eval inputlist) 294(defun eieio-persistent-fix-value (proposed-value)
301 )) 295 "Fix PROPOSED-VALUE.
296Remove leading quotes from lists, and the symbol `list' from the
297head of lists. Explicitly construct any objects found, and strip
298any text properties from string values.
302 299
303(defun eieio-persistent-validate/fix-slot-value (class slot proposed-value) 300This function will descend into the contents of lists, hash
304 "Validate that in CLASS, the SLOT with PROPOSED-VALUE is good, then fix. 301tables, and vectors."
305A limited number of functions, such as quote, list, and valid object
306constructor functions are considered valid.
307Second, any text properties will be stripped from strings."
308 (cond ((consp proposed-value) 302 (cond ((consp proposed-value)
309 ;; Lists with something in them need special treatment. 303 ;; Lists with something in them need special treatment.
310 (let* ((slot-idx (- (eieio--slot-name-index class slot) 304 (cond ((eq (car proposed-value) 'quote)
311 (eval-when-compile eieio--object-num-slots))) 305 (while (eq (car-safe proposed-value) 'quote)
312 (type (cl--slot-descriptor-type (aref (eieio--class-slots class) 306 (setq proposed-value (car (cdr proposed-value))))
313 slot-idx))) 307 proposed-value)
314 (classtype (eieio-persistent-slot-type-is-class-p type))) 308
315 309 ;; An empty list sometimes shows up as (list), which is dumb, but
316 (cond ((eq (car proposed-value) 'quote) 310 ;; we need to support it for backward compar.
317 (car (cdr proposed-value))) 311 ((and (eq (car proposed-value) 'list)
318 312 (= (length proposed-value) 1))
319 ;; An empty list sometimes shows up as (list), which is dumb, but 313 nil)
320 ;; we need to support it for backward compat. 314
321 ((and (eq (car proposed-value) 'list) 315 ;; List of object constructors.
322 (= (length proposed-value) 1)) 316 ((and (eq (car proposed-value) 'list)
323 nil) 317 ;; 2nd item is a list.
324 318 (consp (car (cdr proposed-value)))
325 ;; List of object constructors. 319 ;; 1st elt of 2nd item is a class name.
326 ((and (eq (car proposed-value) 'list) 320 (class-p (car (car (cdr proposed-value)))))
327 ;; 2nd item is a list. 321
328 (consp (car (cdr proposed-value))) 322 ;; We have a list of objects here. Lets load them
329 ;; 1st elt of 2nd item is a class name. 323 ;; in.
330 (class-p (car (car (cdr proposed-value)))) 324 (let ((objlist nil))
331 ) 325 (dolist (subobj (cdr proposed-value))
332 326 (push (eieio-persistent-convert-list-to-object subobj)
333 ;; Check the value against the input class type. 327 objlist))
334 ;; If something goes wrong, issue a smart warning 328 ;; return the list of objects ... reversed.
335 ;; about how a :type is needed for this to work. 329 (nreverse objlist)))
336 (unless (and 330 ;; We have a slot with a single object that can be
337 ;; Do we have a type? 331 ;; saved here. Recurse and evaluate that
338 (consp classtype) (class-p (car classtype))) 332 ;; sub-object.
339 (error "In save file, list of object constructors found, but no :type specified for slot %S of type %S" 333 ((class-p (car proposed-value))
340 slot classtype)) 334 (eieio-persistent-convert-list-to-object
341 335 proposed-value))
342 ;; We have a predicate, but it doesn't satisfy the predicate? 336 (t
343 (dolist (PV (cdr proposed-value)) 337 proposed-value)))
344 (unless (child-of-class-p (car PV) (car classtype))
345 (error "Invalid object: slot member %s does not match class %s"
346 (car PV) (car classtype))))
347
348 ;; We have a list of objects here. Lets load them
349 ;; in.
350 (let ((objlist nil))
351 (dolist (subobj (cdr proposed-value))
352 (push (eieio-persistent-convert-list-to-object subobj)
353 objlist))
354 ;; return the list of objects ... reversed.
355 (nreverse objlist)))
356 ;; We have a slot with a single object that can be
357 ;; saved here. Recurse and evaluate that
358 ;; sub-object.
359 ((and classtype
360 (seq-some
361 (lambda (elt)
362 (child-of-class-p (car proposed-value) elt))
363 (if (listp classtype) classtype (list classtype))))
364 (eieio-persistent-convert-list-to-object
365 proposed-value))
366 (t
367 proposed-value))))
368 ;; For hash-tables and vectors, the top-level `read' will not 338 ;; For hash-tables and vectors, the top-level `read' will not
369 ;; "look inside" member values, so we need to do that 339 ;; "look inside" member values, so we need to do that
370 ;; explicitly. Because `eieio-override-prin1' is recursive in 340 ;; explicitly. Because `eieio-override-prin1' is recursive in
@@ -377,8 +347,7 @@ Second, any text properties will be stripped from strings."
377 (if (class-p (car-safe value)) 347 (if (class-p (car-safe value))
378 (eieio-persistent-convert-list-to-object 348 (eieio-persistent-convert-list-to-object
379 value) 349 value)
380 (eieio-persistent-validate/fix-slot-value 350 (eieio-persistent-fix-value value))))
381 class slot value))))
382 proposed-value) 351 proposed-value)
383 proposed-value) 352 proposed-value)
384 353
@@ -389,70 +358,16 @@ Second, any text properties will be stripped from strings."
389 (if (class-p (car-safe val)) 358 (if (class-p (car-safe val))
390 (eieio-persistent-convert-list-to-object 359 (eieio-persistent-convert-list-to-object
391 val) 360 val)
392 (eieio-persistent-validate/fix-slot-value 361 (eieio-persistent-fix-value val)))))
393 class slot val)))))
394 proposed-value) 362 proposed-value)
395 363
396 ((stringp proposed-value) 364 ((stringp proposed-value)
397 ;; Else, check for strings, remove properties. 365 ;; Else, check for strings, remove properties.
398 (substring-no-properties proposed-value)) 366 (substring-no-properties proposed-value))
399
400 (t
401 ;; Else, just return whatever the constant was.
402 proposed-value))
403 )
404
405(defun eieio-persistent-slot-type-is-class-p (type)
406 "Return the class referred to in TYPE.
407If no class is referenced there, then return nil."
408 (cond ((class-p type)
409 ;; If the type is a class, then return it.
410 type)
411 ((and (eq 'list-of (car-safe type)) (class-p (cadr type)))
412 ;; If it is the type of a list of a class, then return that class and
413 ;; the type.
414 (cons (cadr type) type))
415
416 ((and (symbolp type) (get type 'cl-deftype-handler))
417 ;; Macro-expand the type according to cl-deftype definitions.
418 (eieio-persistent-slot-type-is-class-p
419 (funcall (get type 'cl-deftype-handler))))
420
421 ;; FIXME: foo-child should not be a valid type!
422 ((and (symbolp type) (string-match "-child\\'" (symbol-name type))
423 (class-p (intern-soft (substring (symbol-name type) 0
424 (match-beginning 0)))))
425 (unless eieio-backward-compatibility
426 (error "Use of bogus %S type instead of %S"
427 type (intern-soft (substring (symbol-name type) 0
428 (match-beginning 0)))))
429 ;; If it is the predicate ending with -child, then return
430 ;; that class. Unfortunately, in EIEIO, typep of just the
431 ;; class is the same as if we used -child, so no further work needed.
432 (intern-soft (substring (symbol-name type) 0
433 (match-beginning 0))))
434 ;; FIXME: foo-list should not be a valid type!
435 ((and (symbolp type) (string-match "-list\\'" (symbol-name type))
436 (class-p (intern-soft (substring (symbol-name type) 0
437 (match-beginning 0)))))
438 (unless eieio-backward-compatibility
439 (error "Use of bogus %S type instead of (list-of %S)"
440 type (intern-soft (substring (symbol-name type) 0
441 (match-beginning 0)))))
442 ;; If it is the predicate ending with -list, then return
443 ;; that class and the predicate to use.
444 (cons (intern-soft (substring (symbol-name type) 0
445 (match-beginning 0)))
446 type))
447
448 ((eq (car-safe type) 'or)
449 ;; If type is a list, and is an `or', return all valid class
450 ;; types within the `or' statement.
451 (seq-filter #'eieio-persistent-slot-type-is-class-p (cdr type)))
452 367
453 (t 368 (t
454 ;; No match, not a class. 369 ;; Else, just return whatever the constant was.
455 nil))) 370 proposed-value)))
456 371
457(cl-defmethod object-write ((this eieio-persistent) &optional comment) 372(cl-defmethod object-write ((this eieio-persistent) &optional comment)
458 "Write persistent object THIS out to the current stream. 373 "Write persistent object THIS out to the current stream.