Validatable protocol [Was: Prohibit unsafeBitCast(integer → pointer)]

Validatable can be used in other places as well, making unsafe programming much safer overall. Consider this example:

// sample user structure
struct S {
    var b: Bool = true              // offset 0, size 1
    var int: Int32 = 0x12345678     // offset 4, size 4
    var c: NSObject = NSObject()    // offset 8, size 8
}

In the following code I'm deliberately messing with the underlying bytes simulating a developer error (e.g. due to a typo, lack of knowledge, lack of sleep, etc):

var s = S()
withUnsafeMutableBytes_analogue(&s) { p in
    p[7] = 0xFF                 // messing with integer value - ok
// uncomment one of the following to trigger precondition failure:
//    p[0] = 123                // mess with Bool
//    p[8] |= 1                 // mess with the pointer: make it odd
//    memset(p + 8, 0xF0, 8);   // mess with the pointer: make it bad
//    memset(p + 8, 0, 8)       // mess with the pointer: make it null
}
print("next line")

In all of the uncommented examples the precondition failure was triggered and the app safely terminated right away before the app reaches "next line" - a very nice behaviour compared to what could happen without the checks in-place.

For this user structure the following code is supposed to be autogenerated by the compiler:

// should be automatically generated
extension S: Validatable {
    static func isValid(_ v: UnsafeRawPointer) -> Bool {
        isBoolValid((v + 0).assumingMemoryBound(to: UInt8.self).pointee) &&
        isObjectValid((v + 8).assumingMemoryBound(to: Int.self).pointee)
        // won't check Int - all Int bit patterns are valid
    }
}

Where Validatable protocol is slightly changed compared to the version in one of the messages above:

protocol Validatable {
    static func isValid(_ v: UnsafeRawPointer) -> Bool
}
And validity checks themselves for specific library types are shown here.
func isBoolValid(_ value: UInt8) -> Bool {
    if value == 0 || value == 1 { return true }
    print("strange bool value: \(value)")
    return false
}

func isObjectValid(_ object: Int) -> Bool {
    if object == 0 {
        print("object == nil -> invalid object")
        return false
    }
    if (object & 0x0F) != 0 {
        print("object is not aligned properly -> invalid object")
        return false
    }
    let size = objectSize(object)
    if size == 0 {
        print("object size is 0 -> invalid object")
        return false
    }
    if size < 16 {
        print("object size is too small -> invalid object")
        return false
    }
    if objectClass(object) == nil {
        print("not an object")
        return false
    }
    return true
}

This is a quick prototype of withUnsafeMutableBytes_analogue (obviously in this simple form it lacks all the bells and whistles like throw / re throw, etc). I'm using the C-helper API withUnsafeMutableBytesInternal (see below).

func withUnsafeMutableBytes_analogue<T: Validatable>(_ v: UnsafeMutablePointer<T>, execute block: @escaping (UnsafeMutablePointer<UInt8>) -> Void) {
    withUnsafeMutableBytesInternal(v, block)
    #if DEBUG // release? controllable via diagnostic/sanitising options?
    precondition(T.isValid(v), "invalid value")
    #endif
}
Finally some simple C helpers.
// C.h
typedef void (^BytesBlock)(unsigned char* _Nonnull);
void withUnsafeMutableBytesInternal(void* _Nonnull value, BytesBlock _Nonnull block);
long objectSize(long object);
Class _Nullable objectClass(long object);

// C.m
// compile with -fno-objc-arc
#include "C.h"
#include <objc/runtime.h>
#include <malloc/malloc.h>

void withUnsafeMutableBytesInternal(void* value, BytesBlock block) {
    block(value);
}
long objectSize(long object) {
    return malloc_size((void*)object);
}
Class objectClass(long object) {
    return object_getClass((void*)object);
}

As this discussion progresses it is now clear to me that this is a much bigger safety measure than just one particular check in one particular API. Let me change the subject to match the current vector of discussion.