/// Because Property structs can be constructed from strings that have been /// passed in from the user or are constants CFStringRefs from CoreMidi, we /// need to abstract over how we store their keys. enum PropertyKeyStorage {
Owned(CFString),
Constant(CFStringRef),
}
impl PropertyKeyStorage { /// Return a raw CFStringRef pointing to this property key fn as_string_ref(&self) -> CFStringRef { matchself {
PropertyKeyStorage::Owned(owned) => owned.as_concrete_TypeRef(),
PropertyKeyStorage::Constant(constant) => *constant,
}
}
/// For checking the retain count when debugging #[allow(dead_code)] fn retain_count(&self) -> CFIndex { matchself {
PropertyKeyStorage::Owned(owned) => owned.retain_count(),
PropertyKeyStorage::Constant(constant) => unsafe {
CFGetRetainCount(*constant as CFTypeRef)
},
}
}
}
/// A MIDI object property which value is an String /// pubstruct StringProperty(PropertyKeyStorage);
/// Note: Should only be used internally with predefined CoreMidi constants, /// since it does not bump the retain count of the CFStringRef. fn from_constant_string_ref(string_ref: CFStringRef) -> Self {
StringProperty(PropertyKeyStorage::Constant(string_ref))
}
}
impl<T> PropertyGetter<T> for StringProperty where
T: From<String>,
{ fn value_from(&self, object: &Object) -> Result<T, OSStatus> { let property_key = self.0.as_string_ref(); letmut string_ref = MaybeUninit::uninit(); let status = unsafe { MIDIObjectGetStringProperty(object.0, property_key, string_ref.as_mut_ptr()) };
result_from_status(status, || { let string_ref = unsafe { string_ref.assume_init() }; if string_ref.is_null() { return"".to_string().into();
}; let cf_string: CFString = unsafe { TCFType::wrap_under_create_rule(string_ref) };
cf_string.to_string().into()
})
}
}
impl<'a, T> PropertySetter<T> for StringProperty where
T: Into<String>,
{ fn set_value(&self, object: &Object, value: T) -> Result<(), OSStatus> { let property_key = self.0.as_string_ref(); let value: String = value.into(); let string = CFString::new(&value); let string_ref = string.as_concrete_TypeRef(); let status = unsafe { MIDIObjectSetStringProperty(object.0, property_key, string_ref) };
unit_result_from_status(status)
}
}
/// A MIDI object property which value is an Integer /// pubstruct IntegerProperty(PropertyKeyStorage);
/// Note: Should only be used internally with predefined CoreMidi constants, /// since it does not bump the retain count of the CFStringRef. fn from_constant_string_ref(string_ref: CFStringRef) -> Self {
IntegerProperty(PropertyKeyStorage::Constant(string_ref))
}
}
impl<T> PropertyGetter<T> for IntegerProperty where
T: From<SInt32>,
{ fn value_from(&self, object: &Object) -> Result<T, OSStatus> { let property_key = self.0.as_string_ref(); letmut value = MaybeUninit::uninit(); let status = unsafe { MIDIObjectGetIntegerProperty(object.0, property_key, value.as_mut_ptr()) };
result_from_status(status, || { let value = unsafe { value.assume_init() };
value.into()
})
}
}
impl<T> PropertySetter<T> for IntegerProperty where
T: Into<SInt32>,
{ fn set_value(&self, object: &Object, value: T) -> Result<(), OSStatus> { let property_key = self.0.as_string_ref(); let status = unsafe { MIDIObjectSetIntegerProperty(object.0, property_key, value.into()) };
unit_result_from_status(status)
}
}
/// A MIDI object property which value is a Boolean /// pubstruct BooleanProperty(IntegerProperty);
/// Note: Should only be used internally with predefined CoreMidi constants, /// since it does not bump the retain count of the CFStringRef. fn from_constant_string_ref(string_ref: CFStringRef) -> Self {
BooleanProperty(IntegerProperty::from_constant_string_ref(string_ref))
}
}
fn setup() -> (Client, VirtualDestination) { let client = Client::new("Test Client").unwrap(); let dest = client.virtual_destination(NAME_ORIG, |_| ()).unwrap();
(client, dest)
}
mod string { usesuper::*;
const NAME_MODIFIED: &str = "B";
// Test getting the original value of the "name" property fn check_get_original(property: &StringProperty, dest: &VirtualDestination) { let name: String = property.value_from(dest).unwrap();
assert_eq!(name, NAME_ORIG);
}
// Test setting then getting the "name" property fn check_roundtrip(property: &StringProperty, dest: &VirtualDestination) {
property.set_value(dest, NAME_MODIFIED).unwrap(); let name: String = property.value_from(dest).unwrap();
assert_eq!(name, NAME_MODIFIED);
}
#[test] fn test_from_constant() { let (_client, dest) = setup(); let property = Properties::name();
#[test] fn test_new() { let (_client, dest) = setup(); // "name" is the value of the CoreMidi constant kMIDIPropertyName let property = StringProperty::new("name");
#[test] fn test_not_set() { let (_client, dest) = setup(); // Is not set by default for Virtual Destinations let property = Properties::advance_schedule_time_musec();
let value: Result<i32, _> = property.value_from(&dest);
assert!(value.is_err())
}
#[test] fn test_roundtrip() { let (_client, dest) = setup(); let property = Properties::advance_schedule_time_musec();
property.set_value(&dest, ADVANCED_SCHEDULE_TIME).unwrap(); let num: i32 = property.value_from(&dest).unwrap();
assert_eq!(num, ADVANCED_SCHEDULE_TIME);
}
}
mod boolean { usesuper::*;
#[test] fn test_not_set() { let (_client, dest) = setup(); // Not set by default on Virtual Destinations let property = Properties::transmits_program_changes();
let value: Result<bool, _> = property.value_from(&dest);
assert!(value.is_err())
}
#[test] fn test_roundtrip() { let (_client, dest) = setup(); let property = Properties::private();
property.set_value(&dest, true).unwrap(); let value: bool = property.value_from(&dest).unwrap();
assert_eq!(value, true);
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.