Cannot get vwt.initializeWithCopy
to copy Arrays properly?
#51
-
To recap, I am using Echo to make a JSON object mapper. My library uses the output of struct Person {
/// For testing purposes; this is used as the structure of the "one child"
static let sally = Person(name: "Sally", age: 5, married: false, kids: [], job: nil)
var name: String
var age: Int
var married: Bool
var kids: [Person]
var job: String?
} It looks like the array's backing storage is being released out from under it when the This probably would affect other types of COW collections I assume but so far I am only testing Array. The strings I'm using are static as well, so they would never run into this problem. Here are the relevant code segments: Code// Helper operator intended to cast from one
// pointer type to UnsafeMutableRawPointer
postfix operator ~
postfix func ~<T>(target: T) -> UnsafeMutableRawPointer {
return unsafeBitCast(target, to: UnsafeMutableRawPointer.self)
}
extension StructMetadata {
// Entrypoint for creating struct instance from a property map
func createInstance(props: [String: Any] = [:]) -> Any {
// Precondition: props must contain a key for every property
assert({
let givenKeys = Set(props.keys.map { $0 as String })
let allKeys = Set(self.descriptor.fields.records.map(\.name))
return givenKeys == allKeys
}())
var box = AnyExistentialContainer(metadata: self)
for (key, value) in props {
self.set(value: value, forKey: key, pointer: box.getValueBuffer()~)
}
// At this point, the struct is populated correctly, except
// for array properties which fail to unwrap any elements
return box.toAny
}
func set(value: Any, forKey key: String, pointer ptr: UnsafeMutableRawPointer) {
// These two are absolutely correct
let offset = self.fieldOffset(for: key)!
let type = self.fieldType(for: key)!
ptr.storeBytes(of: value, type: type, offset: offset)
}
}
extension UnsafeMutableRawPointer {
func storeBytes(of value: Any, type: Metadata, offset: Int = 0) {
// Things get wonky here if I don't use my modified version
// of this function to avoid double-boxed containers from #49
var box = container(for: value)
type.vwt.initializeWithCopy((self + offset), box.projectValue()~)
// What I was doing before, which also didn't work for arrays
// (self + offset).copyMemory(from: box.projectValue(), byteCount: type.vwt.size)
}
}
// MARK: Populating AnyExistentialContainer
extension AnyExistentialContainer {
var toAny: Any {
return unsafeBitCast(self, to: Any.self)
}
/// Calls into `projectValue()` but will allocate a box
/// first if needed for types that are not inline
mutating func getValueBuffer() -> UnsafeMutableRawPointer {
// Allocate a box if needed and return it
if !self.metadata.vwt.flags.isValueInline && self.data.0 == 0 {
return self.metadata.allocateBoxForExistential(in: &self)~
}
// We don't need a box or already have one
return self.projectValue()~
}
} What could be going on here? Edit: after updating to your latest commit, I now get |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 13 replies
-
I'm very confused because I'm using your code above and creating my own person instances with kids, and I'm able to see them completely (nothing is wrong on my end). |
Beta Was this translation helpful? Give feedback.
-
When I created the array I'm trying to assign to Solution: use Edit: see Azoy's replies above; |
Beta Was this translation helpful? Give feedback.
When I created the array I'm trying to assign to
kids
, it was created as[Any]
. The property I'm assigning it to is of type[Person]
.Solution: use
swift_dynamicCast
to perform the conversion :)Edit: see Azoy's replies above;
swift_dynamicCast
may not be as good a choice as_openExistential